View Javadoc

1   /*   Copyright 2004 The Apache Software Foundation
2    *
3    *   Licensed under the Apache License, Version 2.0 (the "License");
4    *   you may not use this file except in compliance with the License.
5    *   You may obtain a copy of the License at
6    *
7    *       http://www.apache.org/licenses/LICENSE-2.0
8    *
9    *   Unless required by applicable law or agreed to in writing, software
10   *   distributed under the License is distributed on an "AS IS" BASIS,
11   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   *   See the License for the specific language governing permissions and
13   *  limitations under the License.
14   */
15  
16  package com.eviware.soapui.impl.wsdl.support.xsd;
17  
18  import com.eviware.soapui.SoapUI;
19  import com.eviware.soapui.settings.WsdlSettings;
20  import com.eviware.soapui.support.StringUtils;
21  import org.apache.xmlbeans.*;
22  import org.apache.xmlbeans.impl.util.Base64;
23  import org.apache.xmlbeans.impl.util.HexBin;
24  import org.apache.xmlbeans.soap.SOAPArrayType;
25  import org.apache.xmlbeans.soap.SchemaWSDLArrayType;
26  
27  import javax.xml.namespace.QName;
28  import java.math.BigDecimal;
29  import java.math.BigInteger;
30  import java.util.*;
31  
32  /***
33   * XmlBeans class for generating XML from XML Schemas
34   */
35  
36  public class SampleXmlUtil
37  {
38     private boolean _soapEnc;
39     private boolean _exampleContent = false;
40     private boolean _typeComment = false;
41     private Set<QName> excludedTypes = new HashSet<QName>();
42     private Map<QName, String[]> multiValues = null;
43     private boolean _skipComments;
44  
45     public SampleXmlUtil( boolean soapEnc )
46     {
47        _soapEnc = soapEnc;
48  
49        excludedTypes.addAll( SchemaUtils.getExcludedTypes() );
50     }
51  
52     public boolean isSoapEnc()
53     {
54        return _soapEnc;
55     }
56  
57     public boolean isExampleContent()
58     {
59        return _exampleContent;
60     }
61  
62     public void setExampleContent( boolean content )
63     {
64        _exampleContent = content;
65     }
66  
67     public boolean isTypeComment()
68     {
69        return _typeComment;
70     }
71  
72     public void setTypeComment( boolean comment )
73     {
74        _typeComment = comment;
75     }
76  
77     public void setMultiValues( Map<QName, String[]> multiValues )
78     {
79        this.multiValues = multiValues;
80     }
81  
82     public String createSample( SchemaType sType )
83     {
84        XmlObject object = XmlObject.Factory.newInstance();
85        XmlCursor cursor = object.newCursor();
86        // Skip the document node
87        cursor.toNextToken();
88        // Using the type and the cursor, call the utility method to get a
89        // sample XML payload for that Schema element
90        createSampleForType( sType, cursor );
91        // Cursor now contains the sample payload
92        // Pretty print the result. Note that the cursor is positioned at the
93        // end of the doc so we use the original xml object that the cursor was
94        // created upon to do the xmlText() against.
95  
96        cursor.dispose();
97  
98        XmlOptions options = new XmlOptions();
99        options.put( XmlOptions.SAVE_PRETTY_PRINT );
100       options.put( XmlOptions.SAVE_PRETTY_PRINT_INDENT, 3 );
101       options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
102       options.setSaveOuter();
103       String result = object.xmlText( options );
104 
105       return result;
106    }
107 
108    public static String createSampleForElement( SchemaGlobalElement element )
109    {
110       XmlObject xml = XmlObject.Factory.newInstance();
111 
112       XmlCursor c = xml.newCursor();
113       c.toNextToken();
114       c.beginElement( element.getName() );
115 
116       new SampleXmlUtil( false ).createSampleForType( element.getType(), c );
117 
118       c.dispose();
119 
120       XmlOptions options = new XmlOptions();
121       options.put( XmlOptions.SAVE_PRETTY_PRINT );
122       options.put( XmlOptions.SAVE_PRETTY_PRINT_INDENT, 3 );
123       options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
124       options.setSaveOuter();
125       String result = xml.xmlText( options );
126 
127 
128 
129       return result;
130    }
131 
132    public static String createSampleForType( SchemaType sType )
133    {
134       XmlObject object = XmlObject.Factory.newInstance();
135       XmlCursor cursor = object.newCursor();
136       // Skip the document node
137       cursor.toNextToken();
138       // Using the type and the cursor, call the utility method to get a
139       // sample XML payload for that Schema element
140       new SampleXmlUtil( false ).createSampleForType( sType, cursor );
141       // Cursor now contains the sample payload
142       // Pretty print the result. Note that the cursor is positioned at the
143       // end of the doc so we use the original xml object that the cursor was
144       // created upon to do the xmlText() against.
145 
146       cursor.dispose();
147       XmlOptions options = new XmlOptions();
148       options.put( XmlOptions.SAVE_PRETTY_PRINT );
149       options.put( XmlOptions.SAVE_PRETTY_PRINT_INDENT, 3 );
150       options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
151       options.setSaveOuter();
152       String result = object.xmlText( options );
153 
154       return result;
155    }
156 
157    Random _picker = new Random( 1 );
158 
159    private boolean ignoreOptional;
160 
161    /***
162     * Cursor position Before: <theElement>^</theElement> After: <theElement><lots
163     * of stuff/>^</theElement>
164     */
165    public void createSampleForType( SchemaType stype, XmlCursor xmlc )
166    {
167       _exampleContent = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_TYPE_EXAMPLE_VALUE );
168       _typeComment = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_TYPE_COMMENT_TYPE );
169       _skipComments = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_SKIP_COMMENTS );
170 
171       QName nm = stype.getName();
172       if( nm == null && stype.getContainerField() != null )
173          nm = stype.getContainerField().getName();
174 
175       if( nm != null && excludedTypes.contains( nm ) )
176       {
177          if( !_skipComments )
178             xmlc.insertComment( "Ignoring type [" + nm + "]" );
179          return;
180       }
181 
182       if( _typeStack.contains( stype ) )
183          return;
184 
185       _typeStack.add( stype );
186 
187       try
188       {
189          if( stype.isSimpleType() || stype.isURType() )
190          {
191             processSimpleType( stype, xmlc );
192             return;
193          }
194 
195          // complex Type
196          // <theElement>^</theElement>
197          processAttributes( stype, xmlc );
198 
199          // <theElement attri1="string">^</theElement>
200          switch( stype.getContentType() )
201          {
202             case SchemaType.NOT_COMPLEX_TYPE:
203             case SchemaType.EMPTY_CONTENT:
204                // noop
205                break;
206             case SchemaType.SIMPLE_CONTENT:
207             {
208                processSimpleType( stype, xmlc );
209             }
210             break;
211             case SchemaType.MIXED_CONTENT:
212                xmlc.insertChars( pick( WORDS ) + " " );
213                if( stype.getContentModel() != null )
214                {
215                   processParticle( stype.getContentModel(), xmlc, true );
216                }
217                xmlc.insertChars( pick( WORDS ) );
218                break;
219             case SchemaType.ELEMENT_CONTENT:
220                if( stype.getContentModel() != null )
221                {
222                   processParticle( stype.getContentModel(), xmlc, false );
223                }
224                break;
225          }
226       }
227       finally
228       {
229          _typeStack.remove( _typeStack.size() - 1 );
230       }
231    }
232 
233    private void processSimpleType( SchemaType stype, XmlCursor xmlc )
234    {
235       if( _soapEnc )
236       {
237          QName typeName = stype.getName();
238          if( typeName != null )
239          {
240             xmlc.insertAttributeWithValue( XSI_TYPE, formatQName( xmlc, typeName ) );
241          }
242       }
243 
244       String sample = sampleDataForSimpleType( stype );
245       xmlc.insertChars( sample );
246    }
247 
248    private String sampleDataForSimpleType( SchemaType sType )
249    {
250       // swaRef
251       if( sType.getName() != null )
252       {
253          if( sType.getName().equals( new QName( "http://ws-i.org/profiles/basic/1.1/xsd", "swaRef" ) ) )
254             return "cid:" + (long) (System.currentTimeMillis() * Math.random());
255 
256          // xmime base64
257          if( sType.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "base64Binary" ) ) )
258             return "cid:" + (long) (System.currentTimeMillis() * Math.random());
259 
260          // xmime hexBinary
261          if( sType.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "hexBinary" ) ) )
262             return "cid:" + (long) (System.currentTimeMillis() * Math.random());
263       }
264 
265       SchemaType primitiveType = sType.getPrimitiveType();
266       if( primitiveType != null
267               && (primitiveType.getBuiltinTypeCode() == SchemaType.BTC_BASE_64_BINARY || primitiveType
268               .getBuiltinTypeCode() == SchemaType.BTC_HEX_BINARY) )
269          return "cid:" + (long) (System.currentTimeMillis() * Math.random());
270 
271       // if( sType != null )
272       if( !_exampleContent )
273          return "?";
274 
275       if( XmlObject.type.equals( sType ) )
276          return "anyType";
277 
278       if( XmlAnySimpleType.type.equals( sType ) )
279          return "anySimpleType";
280 
281       if( sType.getSimpleVariety() == SchemaType.LIST )
282       {
283          SchemaType itemType = sType.getListItemType();
284          StringBuffer sb = new StringBuffer();
285          int length = pickLength( sType );
286          if( length > 0 )
287             sb.append( sampleDataForSimpleType( itemType ) );
288          for( int i = 1; i < length; i += 1 )
289          {
290             sb.append( ' ' );
291             sb.append( sampleDataForSimpleType( itemType ) );
292          }
293          return sb.toString();
294       }
295 
296       if( sType.getSimpleVariety() == SchemaType.UNION )
297       {
298          SchemaType[] possibleTypes = sType.getUnionConstituentTypes();
299          if( possibleTypes.length == 0 )
300             return "";
301          return sampleDataForSimpleType( possibleTypes[pick( possibleTypes.length )] );
302       }
303 
304       XmlAnySimpleType[] enumValues = sType.getEnumerationValues();
305       if( enumValues != null && enumValues.length > 0 )
306       {
307          return enumValues[pick( enumValues.length )].getStringValue();
308       }
309 
310       switch( primitiveType.getBuiltinTypeCode() )
311       {
312          default:
313          case SchemaType.BTC_NOT_BUILTIN:
314             return "";
315 
316          case SchemaType.BTC_ANY_TYPE:
317          case SchemaType.BTC_ANY_SIMPLE:
318             return "anything";
319 
320          case SchemaType.BTC_BOOLEAN:
321             return pick( 2 ) == 0 ? "true" : "false";
322 
323          case SchemaType.BTC_BASE_64_BINARY:
324          {
325             String result = null;
326             try
327             {
328                result = new String( Base64.encode( formatToLength( pick( WORDS ), sType ).getBytes( "utf-8" ) ) );
329             }
330             catch( java.io.UnsupportedEncodingException e )
331             {
332             }
333             return result;
334          }
335 
336          case SchemaType.BTC_HEX_BINARY:
337             return HexBin.encode( formatToLength( pick( WORDS ), sType ) );
338 
339          case SchemaType.BTC_ANY_URI:
340             return formatToLength( "http://www." + pick( DNS1 ) + "." + pick( DNS2 ) + "/" + pick( WORDS ) + "/"
341                     + pick( WORDS ), sType );
342 
343          case SchemaType.BTC_QNAME:
344             return formatToLength( "qname", sType );
345 
346          case SchemaType.BTC_NOTATION:
347             return formatToLength( "notation", sType );
348 
349          case SchemaType.BTC_FLOAT:
350             return "1.5E2";
351          case SchemaType.BTC_DOUBLE:
352             return "1.051732E7";
353          case SchemaType.BTC_DECIMAL:
354             switch( closestBuiltin( sType ).getBuiltinTypeCode() )
355             {
356                case SchemaType.BTC_SHORT:
357                   return formatDecimal( "1", sType );
358                case SchemaType.BTC_UNSIGNED_SHORT:
359                   return formatDecimal( "5", sType );
360                case SchemaType.BTC_BYTE:
361                   return formatDecimal( "2", sType );
362                case SchemaType.BTC_UNSIGNED_BYTE:
363                   return formatDecimal( "6", sType );
364                case SchemaType.BTC_INT:
365                   return formatDecimal( "3", sType );
366                case SchemaType.BTC_UNSIGNED_INT:
367                   return formatDecimal( "7", sType );
368                case SchemaType.BTC_LONG:
369                   return formatDecimal( "10", sType );
370                case SchemaType.BTC_UNSIGNED_LONG:
371                   return formatDecimal( "11", sType );
372                case SchemaType.BTC_INTEGER:
373                   return formatDecimal( "100", sType );
374                case SchemaType.BTC_NON_POSITIVE_INTEGER:
375                   return formatDecimal( "-200", sType );
376                case SchemaType.BTC_NEGATIVE_INTEGER:
377                   return formatDecimal( "-201", sType );
378                case SchemaType.BTC_NON_NEGATIVE_INTEGER:
379                   return formatDecimal( "200", sType );
380                case SchemaType.BTC_POSITIVE_INTEGER:
381                   return formatDecimal( "201", sType );
382                default:
383                case SchemaType.BTC_DECIMAL:
384                   return formatDecimal( "1000.00", sType );
385             }
386 
387          case SchemaType.BTC_STRING:
388          {
389             String result;
390             switch( closestBuiltin( sType ).getBuiltinTypeCode() )
391             {
392                case SchemaType.BTC_STRING:
393                case SchemaType.BTC_NORMALIZED_STRING:
394                   result = pick( WORDS, _picker.nextInt( 3 ) );
395                   break;
396 
397                case SchemaType.BTC_TOKEN:
398                   result = pick( WORDS, _picker.nextInt( 3 ) );
399                   break;
400 
401                default:
402                   result = pick( WORDS, _picker.nextInt( 3 ) );
403                   break;
404             }
405 
406             return formatToLength( result, sType );
407          }
408 
409          case SchemaType.BTC_DURATION:
410             return formatDuration( sType );
411 
412          case SchemaType.BTC_DATE_TIME:
413          case SchemaType.BTC_TIME:
414          case SchemaType.BTC_DATE:
415          case SchemaType.BTC_G_YEAR_MONTH:
416          case SchemaType.BTC_G_YEAR:
417          case SchemaType.BTC_G_MONTH_DAY:
418          case SchemaType.BTC_G_DAY:
419          case SchemaType.BTC_G_MONTH:
420             return formatDate( sType );
421 
422       }
423    }
424 
425    // a bit from the Aenid
426    public static final String[] WORDS = new String[] { "ipsa", "iovis", "rapidum", "iaculata", "e", "nubibus", "ignem",
427            "disiecitque", "rates", "evertitque", "aequora", "ventis", "illum", "exspirantem", "transfixo", "pectore",
428            "flammas", "turbine", "corripuit", "scopuloque", "infixit", "acuto", "ast", "ego", "quae", "divum",
429            "incedo", "regina", "iovisque", "et", "soror", "et", "coniunx", "una", "cum", "gente", "tot", "annos",
430            "bella", "gero", "et", "quisquam", "numen", "iunonis", "adorat", "praeterea", "aut", "supplex", "aris",
431            "imponet", "honorem", "talia", "flammato", "secum", "dea", "corde", "volutans", "nimborum", "in",
432            "patriam", "loca", "feta", "furentibus", "austris", "aeoliam", "venit", "hic", "vasto", "rex", "aeolus",
433            "antro", "luctantis", "ventos", "tempestatesque", "sonoras", "imperio", "premit", "ac", "vinclis", "et",
434            "carcere", "frenat", "illi", "indignantes", "magno", "cum", "murmure", "montis", "circum", "claustra",
435            "fremunt", "celsa", "sedet", "aeolus", "arce", "sceptra", "tenens", "mollitque", "animos", "et",
436            "temperat", "iras", "ni", "faciat", "maria", "ac", "terras", "caelumque", "profundum", "quippe", "ferant",
437            "rapidi", "secum", "verrantque", "per", "auras", "sed", "pater", "omnipotens", "speluncis", "abdidit",
438            "atris", "hoc", "metuens", "molemque", "et", "montis", "insuper", "altos", "imposuit", "regemque", "dedit",
439            "qui", "foedere", "certo", "et", "premere", "et", "laxas", "sciret", "dare", "iussus", "habenas", };
440 
441    private static final String[] DNS1 = new String[] { "corp", "your", "my", "sample", "company", "test", "any" };
442    private static final String[] DNS2 = new String[] { "com", "org", "com", "gov", "org", "com", "org", "com", "edu" };
443 
444    private int pick( int n )
445    {
446       return _picker.nextInt( n );
447    }
448 
449    private String pick( String[] a )
450    {
451       return a[pick( a.length )];
452    }
453 
454    private String pick( String[] a, int count )
455    {
456       if( count <= 0 )
457          count = 1;
458       // return "";
459 
460       int i = pick( a.length );
461       StringBuffer sb = new StringBuffer( a[i] );
462       while( count-- > 0 )
463       {
464          i += 1;
465          if( i >= a.length )
466             i = 0;
467          sb.append( ' ' );
468          sb.append( a[i] );
469       }
470       return sb.toString();
471    }
472 
473    private String pickDigits( int digits )
474    {
475       StringBuffer sb = new StringBuffer();
476       while( digits-- > 0 )
477          sb.append( Integer.toString( pick( 10 ) ) );
478       return sb.toString();
479    }
480 
481    private int pickLength( SchemaType sType )
482    {
483       XmlInteger length = (XmlInteger) sType.getFacet( SchemaType.FACET_LENGTH );
484       if( length != null )
485          return length.getBigIntegerValue().intValue();
486       XmlInteger min = (XmlInteger) sType.getFacet( SchemaType.FACET_MIN_LENGTH );
487       XmlInteger max = (XmlInteger) sType.getFacet( SchemaType.FACET_MAX_LENGTH );
488       int minInt, maxInt;
489       if( min == null )
490          minInt = 0;
491       else
492          minInt = min.getBigIntegerValue().intValue();
493       if( max == null )
494          maxInt = Integer.MAX_VALUE;
495       else
496          maxInt = max.getBigIntegerValue().intValue();
497       // We try to keep the length of the array within reasonable limits,
498       // at least 1 item and at most 3 if possible
499       if( minInt == 0 && maxInt >= 1 )
500          minInt = 1;
501       if( maxInt > minInt + 2 )
502          maxInt = minInt + 2;
503       if( maxInt < minInt )
504          maxInt = minInt;
505       return minInt + pick( maxInt - minInt );
506    }
507 
508    /***
509     * Formats a given string to the required length, using the following
510     * operations: - append the source string to itself as necessary to pass the
511     * minLength; - truncate the result of previous step, if necessary, to keep
512     * it within minLength.
513     */
514    private String formatToLength( String s, SchemaType sType )
515    {
516       String result = s;
517       try
518       {
519          SimpleValue min = (SimpleValue) sType.getFacet( SchemaType.FACET_LENGTH );
520          if( min == null )
521             min = (SimpleValue) sType.getFacet( SchemaType.FACET_MIN_LENGTH );
522          if( min != null )
523          {
524             int len = min.getIntValue();
525             while( result.length() < len )
526                result = result + result;
527          }
528          SimpleValue max = (SimpleValue) sType.getFacet( SchemaType.FACET_LENGTH );
529          if( max == null )
530             max = (SimpleValue) sType.getFacet( SchemaType.FACET_MAX_LENGTH );
531          if( max != null )
532          {
533             int len = max.getIntValue();
534             if( result.length() > len )
535                result = result.substring( 0, len );
536          }
537       }
538       catch( Exception e ) // intValue can be out of range
539       {
540       }
541       return result;
542    }
543 
544    private String formatDecimal( String start, SchemaType sType )
545    {
546       BigDecimal result = new BigDecimal( start );
547       XmlDecimal xmlD;
548       xmlD = (XmlDecimal) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
549       BigDecimal min = xmlD != null ? xmlD.getBigDecimalValue() : null;
550       xmlD = (XmlDecimal) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
551       BigDecimal max = xmlD != null ? xmlD.getBigDecimalValue() : null;
552       boolean minInclusive = true, maxInclusive = true;
553       xmlD = (XmlDecimal) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
554       if( xmlD != null )
555       {
556          BigDecimal minExcl = xmlD.getBigDecimalValue();
557          if( min == null || min.compareTo( minExcl ) < 0 )
558          {
559             min = minExcl;
560             minInclusive = false;
561          }
562       }
563       xmlD = (XmlDecimal) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
564       if( xmlD != null )
565       {
566          BigDecimal maxExcl = xmlD.getBigDecimalValue();
567          if( max == null || max.compareTo( maxExcl ) > 0 )
568          {
569             max = maxExcl;
570             maxInclusive = false;
571          }
572       }
573       xmlD = (XmlDecimal) sType.getFacet( SchemaType.FACET_TOTAL_DIGITS );
574       int totalDigits = -1;
575       if( xmlD != null )
576       {
577          totalDigits = xmlD.getBigDecimalValue().intValue();
578 
579          StringBuffer sb = new StringBuffer( totalDigits );
580          for( int i = 0; i < totalDigits; i++ )
581             sb.append( '9' );
582          BigDecimal digitsLimit = new BigDecimal( sb.toString() );
583          if( max != null && max.compareTo( digitsLimit ) > 0 )
584          {
585             max = digitsLimit;
586             maxInclusive = true;
587          }
588          digitsLimit = digitsLimit.negate();
589          if( min != null && min.compareTo( digitsLimit ) < 0 )
590          {
591             min = digitsLimit;
592             minInclusive = true;
593          }
594       }
595 
596       int sigMin = min == null ? 1 : result.compareTo( min );
597       int sigMax = max == null ? -1 : result.compareTo( max );
598       boolean minOk = sigMin > 0 || sigMin == 0 && minInclusive;
599       boolean maxOk = sigMax < 0 || sigMax == 0 && maxInclusive;
600 
601       // Compute the minimum increment
602       xmlD = (XmlDecimal) sType.getFacet( SchemaType.FACET_FRACTION_DIGITS );
603       int fractionDigits = -1;
604       BigDecimal increment;
605       if( xmlD == null )
606          increment = new BigDecimal( 1 );
607       else
608       {
609          fractionDigits = xmlD.getBigDecimalValue().intValue();
610          if( fractionDigits > 0 )
611          {
612             StringBuffer sb = new StringBuffer( "0." );
613             for( int i = 1; i < fractionDigits; i++ )
614                sb.append( '0' );
615             sb.append( '1' );
616             increment = new BigDecimal( sb.toString() );
617          }
618          else
619             increment = new BigDecimal( 1 );
620       }
621 
622       if( minOk && maxOk )
623       {
624          // OK
625       }
626       else if( minOk && !maxOk )
627       {
628          // TOO BIG
629          if( maxInclusive )
630             result = max;
631          else
632             result = max.subtract( increment );
633       }
634       else if( !minOk && maxOk )
635       {
636          // TOO SMALL
637          if( minInclusive )
638             result = min;
639          else
640             result = min.add( increment );
641       }
642       else
643       {
644          // MIN > MAX!!
645       }
646 
647       // We have the number
648       // Adjust the scale according to the totalDigits and fractionDigits
649       int digits = 0;
650       BigDecimal ONE = new BigDecimal( BigInteger.ONE );
651       for( BigDecimal n = result; n.abs().compareTo( ONE ) >= 0; digits++ )
652          n = n.movePointLeft( 1 );
653 
654       if( fractionDigits > 0 )
655          if( totalDigits >= 0 )
656             result.setScale( Math.max( fractionDigits, totalDigits - digits ) );
657          else
658             result.setScale( fractionDigits );
659       else if( fractionDigits == 0 )
660          result.setScale( 0 );
661 
662       return result.toString();
663    }
664 
665    private String formatDuration( SchemaType sType )
666    {
667       XmlDuration d = (XmlDuration) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
668       GDuration minInclusive = null;
669       if( d != null )
670          minInclusive = d.getGDurationValue();
671 
672       d = (XmlDuration) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
673       GDuration maxInclusive = null;
674       if( d != null )
675          maxInclusive = d.getGDurationValue();
676 
677       d = (XmlDuration) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
678       GDuration minExclusive = null;
679       if( d != null )
680          minExclusive = d.getGDurationValue();
681 
682       d = (XmlDuration) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
683       GDuration maxExclusive = null;
684       if( d != null )
685          maxExclusive = d.getGDurationValue();
686 
687       GDurationBuilder gdurb = new GDurationBuilder();
688       BigInteger min, max;
689 
690       gdurb.setSecond( pick( 800000 ) );
691       gdurb.setMonth( pick( 20 ) );
692 
693       // Years
694       // Months
695       // Days
696       // Hours
697       // Minutes
698       // Seconds
699       // Fractions
700       if( minInclusive != null )
701       {
702          if( gdurb.getYear() < minInclusive.getYear() )
703             gdurb.setYear( minInclusive.getYear() );
704          if( gdurb.getMonth() < minInclusive.getMonth() )
705             gdurb.setMonth( minInclusive.getMonth() );
706          if( gdurb.getDay() < minInclusive.getDay() )
707             gdurb.setDay( minInclusive.getDay() );
708          if( gdurb.getHour() < minInclusive.getHour() )
709             gdurb.setHour( minInclusive.getHour() );
710          if( gdurb.getMinute() < minInclusive.getMinute() )
711             gdurb.setMinute( minInclusive.getMinute() );
712          if( gdurb.getSecond() < minInclusive.getSecond() )
713             gdurb.setSecond( minInclusive.getSecond() );
714          if( gdurb.getFraction().compareTo( minInclusive.getFraction() ) < 0 )
715             gdurb.setFraction( minInclusive.getFraction() );
716       }
717 
718       if( maxInclusive != null )
719       {
720          if( gdurb.getYear() > maxInclusive.getYear() )
721             gdurb.setYear( maxInclusive.getYear() );
722          if( gdurb.getMonth() > maxInclusive.getMonth() )
723             gdurb.setMonth( maxInclusive.getMonth() );
724          if( gdurb.getDay() > maxInclusive.getDay() )
725             gdurb.setDay( maxInclusive.getDay() );
726          if( gdurb.getHour() > maxInclusive.getHour() )
727             gdurb.setHour( maxInclusive.getHour() );
728          if( gdurb.getMinute() > maxInclusive.getMinute() )
729             gdurb.setMinute( maxInclusive.getMinute() );
730          if( gdurb.getSecond() > maxInclusive.getSecond() )
731             gdurb.setSecond( maxInclusive.getSecond() );
732          if( gdurb.getFraction().compareTo( maxInclusive.getFraction() ) > 0 )
733             gdurb.setFraction( maxInclusive.getFraction() );
734       }
735 
736       if( minExclusive != null )
737       {
738          if( gdurb.getYear() <= minExclusive.getYear() )
739             gdurb.setYear( minExclusive.getYear() + 1 );
740          if( gdurb.getMonth() <= minExclusive.getMonth() )
741             gdurb.setMonth( minExclusive.getMonth() + 1 );
742          if( gdurb.getDay() <= minExclusive.getDay() )
743             gdurb.setDay( minExclusive.getDay() + 1 );
744          if( gdurb.getHour() <= minExclusive.getHour() )
745             gdurb.setHour( minExclusive.getHour() + 1 );
746          if( gdurb.getMinute() <= minExclusive.getMinute() )
747             gdurb.setMinute( minExclusive.getMinute() + 1 );
748          if( gdurb.getSecond() <= minExclusive.getSecond() )
749             gdurb.setSecond( minExclusive.getSecond() + 1 );
750          if( gdurb.getFraction().compareTo( minExclusive.getFraction() ) <= 0 )
751             gdurb.setFraction( minExclusive.getFraction().add( new BigDecimal( 0.001 ) ) );
752       }
753 
754       if( maxExclusive != null )
755       {
756          if( gdurb.getYear() > maxExclusive.getYear() )
757             gdurb.setYear( maxExclusive.getYear() );
758          if( gdurb.getMonth() > maxExclusive.getMonth() )
759             gdurb.setMonth( maxExclusive.getMonth() );
760          if( gdurb.getDay() > maxExclusive.getDay() )
761             gdurb.setDay( maxExclusive.getDay() );
762          if( gdurb.getHour() > maxExclusive.getHour() )
763             gdurb.setHour( maxExclusive.getHour() );
764          if( gdurb.getMinute() > maxExclusive.getMinute() )
765             gdurb.setMinute( maxExclusive.getMinute() );
766          if( gdurb.getSecond() > maxExclusive.getSecond() )
767             gdurb.setSecond( maxExclusive.getSecond() );
768          if( gdurb.getFraction().compareTo( maxExclusive.getFraction() ) > 0 )
769             gdurb.setFraction( maxExclusive.getFraction() );
770       }
771 
772       gdurb.normalize();
773       return gdurb.toString();
774    }
775 
776    private String formatDate( SchemaType sType )
777    {
778       GDateBuilder gdateb = new GDateBuilder( new Date( 1000L * pick( 365 * 24 * 60 * 60 ) + (30L + pick( 20 )) * 365
779               * 24 * 60 * 60 * 1000 ) );
780       GDate min = null, max = null;
781       GDate temp;
782 
783       // Find the min and the max according to the type
784       switch( sType.getPrimitiveType().getBuiltinTypeCode() )
785       {
786          case SchemaType.BTC_DATE_TIME:
787          {
788             XmlDateTime x = (XmlDateTime) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
789             if( x != null )
790                min = x.getGDateValue();
791             x = (XmlDateTime) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
792             if( x != null )
793                if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
794                   min = x.getGDateValue();
795 
796             x = (XmlDateTime) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
797             if( x != null )
798                max = x.getGDateValue();
799             x = (XmlDateTime) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
800             if( x != null )
801                if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
802                   max = x.getGDateValue();
803             break;
804          }
805          case SchemaType.BTC_TIME:
806          {
807             XmlTime x = (XmlTime) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
808             if( x != null )
809                min = x.getGDateValue();
810             x = (XmlTime) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
811             if( x != null )
812                if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
813                   min = x.getGDateValue();
814 
815             x = (XmlTime) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
816             if( x != null )
817                max = x.getGDateValue();
818             x = (XmlTime) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
819             if( x != null )
820                if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
821                   max = x.getGDateValue();
822             break;
823          }
824          case SchemaType.BTC_DATE:
825          {
826             XmlDate x = (XmlDate) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
827             if( x != null )
828                min = x.getGDateValue();
829             x = (XmlDate) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
830             if( x != null )
831                if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
832                   min = x.getGDateValue();
833 
834             x = (XmlDate) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
835             if( x != null )
836                max = x.getGDateValue();
837             x = (XmlDate) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
838             if( x != null )
839                if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
840                   max = x.getGDateValue();
841             break;
842          }
843          case SchemaType.BTC_G_YEAR_MONTH:
844          {
845             XmlGYearMonth x = (XmlGYearMonth) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
846             if( x != null )
847                min = x.getGDateValue();
848             x = (XmlGYearMonth) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
849             if( x != null )
850                if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
851                   min = x.getGDateValue();
852 
853             x = (XmlGYearMonth) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
854             if( x != null )
855                max = x.getGDateValue();
856             x = (XmlGYearMonth) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
857             if( x != null )
858                if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
859                   max = x.getGDateValue();
860             break;
861          }
862          case SchemaType.BTC_G_YEAR:
863          {
864             XmlGYear x = (XmlGYear) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
865             if( x != null )
866                min = x.getGDateValue();
867             x = (XmlGYear) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
868             if( x != null )
869                if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
870                   min = x.getGDateValue();
871 
872             x = (XmlGYear) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
873             if( x != null )
874                max = x.getGDateValue();
875             x = (XmlGYear) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
876             if( x != null )
877                if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
878                   max = x.getGDateValue();
879             break;
880          }
881          case SchemaType.BTC_G_MONTH_DAY:
882          {
883             XmlGMonthDay x = (XmlGMonthDay) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
884             if( x != null )
885                min = x.getGDateValue();
886             x = (XmlGMonthDay) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
887             if( x != null )
888                if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
889                   min = x.getGDateValue();
890 
891             x = (XmlGMonthDay) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
892             if( x != null )
893                max = x.getGDateValue();
894             x = (XmlGMonthDay) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
895             if( x != null )
896                if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
897                   max = x.getGDateValue();
898             break;
899          }
900          case SchemaType.BTC_G_DAY:
901          {
902             XmlGDay x = (XmlGDay) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
903             if( x != null )
904                min = x.getGDateValue();
905             x = (XmlGDay) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
906             if( x != null )
907                if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
908                   min = x.getGDateValue();
909 
910             x = (XmlGDay) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
911             if( x != null )
912                max = x.getGDateValue();
913             x = (XmlGDay) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
914             if( x != null )
915                if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
916                   max = x.getGDateValue();
917             break;
918          }
919          case SchemaType.BTC_G_MONTH:
920          {
921             XmlGMonth x = (XmlGMonth) sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
922             if( x != null )
923                min = x.getGDateValue();
924             x = (XmlGMonth) sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
925             if( x != null )
926                if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
927                   min = x.getGDateValue();
928 
929             x = (XmlGMonth) sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
930             if( x != null )
931                max = x.getGDateValue();
932             x = (XmlGMonth) sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
933             if( x != null )
934                if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
935                   max = x.getGDateValue();
936             break;
937          }
938       }
939 
940       if( min != null && max == null )
941       {
942          if( min.compareToGDate( gdateb ) >= 0 )
943          {
944             // Reset the date to min + (1-8) hours
945             Calendar c = gdateb.getCalendar();
946             c.add( Calendar.HOUR_OF_DAY, pick( 8 ) );
947             gdateb = new GDateBuilder( c );
948          }
949       }
950       else if( min == null && max != null )
951       {
952          if( max.compareToGDate( gdateb ) <= 0 )
953          {
954             // Reset the date to max - (1-8) hours
955             Calendar c = gdateb.getCalendar();
956             c.add( Calendar.HOUR_OF_DAY, 0 - pick( 8 ) );
957             gdateb = new GDateBuilder( c );
958          }
959       }
960       else if( min != null && max != null )
961       {
962          if( min.compareToGDate( gdateb ) >= 0 || max.compareToGDate( gdateb ) <= 0 )
963          {
964             // Find a date between the two
965             Calendar c = min.getCalendar();
966             Calendar cmax = max.getCalendar();
967             c.add( Calendar.HOUR_OF_DAY, 1 );
968             if( c.after( cmax ) )
969             {
970                c.add( Calendar.HOUR_OF_DAY, -1 );
971                c.add( Calendar.MINUTE, 1 );
972                if( c.after( cmax ) )
973                {
974                   c.add( Calendar.MINUTE, -1 );
975                   c.add( Calendar.SECOND, 1 );
976                   if( c.after( cmax ) )
977                   {
978                      c.add( Calendar.SECOND, -1 );
979                      c.add( Calendar.MILLISECOND, 1 );
980                      if( c.after( cmax ) )
981                         c.add( Calendar.MILLISECOND, -1 );
982                   }
983                }
984             }
985             gdateb = new GDateBuilder( c );
986          }
987       }
988 
989       gdateb.setBuiltinTypeCode( sType.getPrimitiveType().getBuiltinTypeCode() );
990       if( pick( 2 ) == 0 )
991          gdateb.clearTimeZone();
992       return gdateb.toString();
993    }
994 
995    private SchemaType closestBuiltin( SchemaType sType )
996    {
997       while( !sType.isBuiltinType() )
998          sType = sType.getBaseType();
999       return sType;
1000    }
1001 
1002    /***
1003     * Cracks a combined QName of the form URL:localname
1004     */
1005    public static QName crackQName( String qName )
1006    {
1007       String ns;
1008       String name;
1009 
1010       int index = qName.lastIndexOf( ':' );
1011       if( index >= 0 )
1012       {
1013          ns = qName.substring( 0, index );
1014          name = qName.substring( index + 1 );
1015       }
1016       else
1017       {
1018          ns = "";
1019          name = qName;
1020       }
1021 
1022       return new QName( ns, name );
1023    }
1024 
1025    /***
1026     * Cursor position: Before this call: <outer><foo/>^</outer> (cursor at the ^)
1027     * After this call: <<outer><foo/><bar/>som text<etc/>^</outer>
1028     */
1029    private void processParticle( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1030    {
1031       int loop = determineMinMaxForSample( sp, xmlc );
1032 
1033       while( loop-- > 0 )
1034       {
1035          switch( sp.getParticleType() )
1036          {
1037             case (SchemaParticle.ELEMENT):
1038                processElement( sp, xmlc, mixed );
1039                break;
1040             case (SchemaParticle.SEQUENCE):
1041                processSequence( sp, xmlc, mixed );
1042                break;
1043             case (SchemaParticle.CHOICE):
1044                processChoice( sp, xmlc, mixed );
1045                break;
1046             case (SchemaParticle.ALL):
1047                processAll( sp, xmlc, mixed );
1048                break;
1049             case (SchemaParticle.WILDCARD):
1050                processWildCard( sp, xmlc, mixed );
1051                break;
1052             default:
1053                // throw new Exception("No Match on Schema Particle Type: " +
1054                // String.valueOf(sp.getParticleType()));
1055          }
1056       }
1057    }
1058 
1059    private int determineMinMaxForSample( SchemaParticle sp, XmlCursor xmlc )
1060    {
1061       int minOccurs = sp.getIntMinOccurs();
1062       int maxOccurs = sp.getIntMaxOccurs();
1063 
1064       if( minOccurs == maxOccurs )
1065          return minOccurs;
1066 
1067       if( minOccurs == 0 && ignoreOptional )
1068          return 0;
1069 
1070       int result = minOccurs;
1071       if( result == 0 )
1072          result = 1;
1073 
1074       if( sp.getParticleType() != SchemaParticle.ELEMENT )
1075          return result;
1076 
1077       // it probably only makes sense to put comments in front of individual
1078       // elements that repeat
1079 
1080       if( !_skipComments )
1081       {
1082          if( sp.getMaxOccurs() == null )
1083          {
1084             // xmlc.insertComment("The next " + getItemNameOrType(sp, xmlc) + " may
1085             // be repeated " + minOccurs + " or more times");
1086             if( minOccurs == 0 )
1087                xmlc.insertComment( "Zero or more repetitions:" );
1088             else
1089                xmlc.insertComment( minOccurs + " or more repetitions:" );
1090          }
1091          else if( sp.getIntMaxOccurs() > 1 )
1092          {
1093             xmlc.insertComment( minOccurs + " to " + String.valueOf( sp.getMaxOccurs() ) + " repetitions:" );
1094          }
1095          else
1096          {
1097             xmlc.insertComment( "Optional:" );
1098          }
1099       }
1100 
1101       return result;
1102    }
1103 
1104    /*
1105      * Return a name for the element or the particle type to use in the comment
1106      * for minoccurs, max occurs
1107      */
1108    private String getItemNameOrType( SchemaParticle sp, XmlCursor xmlc )
1109    {
1110       String elementOrTypeName = null;
1111       if( sp.getParticleType() == SchemaParticle.ELEMENT )
1112       {
1113          elementOrTypeName = "Element (" + sp.getName().getLocalPart() + ")";
1114       }
1115       else
1116       {
1117          elementOrTypeName = printParticleType( sp.getParticleType() );
1118       }
1119       return elementOrTypeName;
1120    }
1121 
1122    private void processElement( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1123    {
1124       // cast as schema local element
1125       SchemaLocalElement element = (SchemaLocalElement) sp;
1126 
1127       // Add comment about type
1128       addElementTypeAndRestricionsComment( element, xmlc );
1129 
1130       // / ^ -> <elemenname></elem>^
1131       if( _soapEnc )
1132          xmlc.insertElement( element.getName().getLocalPart() ); // soap
1133          // encoded?
1134          // drop
1135          // namespaces.
1136       else
1137          xmlc.insertElement( element.getName().getLocalPart(), element.getName().getNamespaceURI() );
1138       // / -> <elem>^</elem>
1139       // processAttributes( sp.getType(), xmlc );
1140 
1141       xmlc.toPrevToken();
1142       // -> <elem>stuff^</elem>
1143 
1144       String[] values = null;
1145       if( multiValues != null )
1146          values = multiValues.get( element.getName() );
1147       if( values != null )
1148          xmlc.insertChars( StringUtils.join( values, "," ) );
1149       else if( sp.isDefault() )
1150          xmlc.insertChars( sp.getDefaultText() );
1151       else
1152          createSampleForType( element.getType(), xmlc );
1153       // -> <elem>stuff</elem>^
1154       xmlc.toNextToken();
1155    }
1156 
1157    private void moveToken( int numToMove, XmlCursor xmlc )
1158    {
1159       for( int i = 0; i < Math.abs( numToMove ); i++ )
1160       {
1161          if( numToMove < 0 )
1162          {
1163             xmlc.toPrevToken();
1164          }
1165          else
1166          {
1167             xmlc.toNextToken();
1168          }
1169       }
1170    }
1171 
1172    private static final String formatQName( XmlCursor xmlc, QName qName )
1173    {
1174       XmlCursor parent = xmlc.newCursor();
1175       parent.toParent();
1176       String prefix = parent.prefixForNamespace( qName.getNamespaceURI() );
1177       parent.dispose();
1178       String name;
1179       if( prefix == null || prefix.length() == 0 )
1180          name = qName.getLocalPart();
1181       else
1182          name = prefix + ":" + qName.getLocalPart();
1183       return name;
1184    }
1185 
1186    private static final QName HREF = new QName( "href" );
1187    private static final QName ID = new QName( "id" );
1188    public static final QName XSI_TYPE = new QName( "http://www.w3.org/2001/XMLSchema-instance", "type" );
1189    public static final QName ENC_ARRAYTYPE = new QName( "http://schemas.xmlsoap.org/soap/encoding/", "arrayType" );
1190    private static final QName ENC_OFFSET = new QName( "http://schemas.xmlsoap.org/soap/encoding/", "offset" );
1191 
1192    public static final Set<QName> SKIPPED_SOAP_ATTRS = new HashSet<QName>( Arrays.asList( new QName[] { HREF, ID,
1193            ENC_OFFSET } ) );
1194 
1195    private void processAttributes( SchemaType stype, XmlCursor xmlc )
1196    {
1197       if( _soapEnc )
1198       {
1199          QName typeName = stype.getName();
1200          if( typeName != null )
1201          {
1202             xmlc.insertAttributeWithValue( XSI_TYPE, formatQName( xmlc, typeName ) );
1203          }
1204       }
1205 
1206       SchemaProperty[] attrProps = stype.getAttributeProperties();
1207       for( int i = 0; i < attrProps.length; i++ )
1208       {
1209          SchemaProperty attr = attrProps[i];
1210 
1211          if( attr.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "contentType" ) ) )
1212          {
1213             xmlc.insertAttributeWithValue( attr.getName(), "application/?" );
1214             continue;
1215          }
1216 
1217          if( _soapEnc )
1218          {
1219             if( SKIPPED_SOAP_ATTRS.contains( attr.getName() ) )
1220                continue;
1221             if( ENC_ARRAYTYPE.equals( attr.getName() ) )
1222             {
1223                SOAPArrayType arrayType = ((SchemaWSDLArrayType) stype.getAttributeModel().getAttribute(
1224                        attr.getName() )).getWSDLArrayType();
1225                if( arrayType != null )
1226                   xmlc.insertAttributeWithValue( attr.getName(), formatQName( xmlc, arrayType.getQName() )
1227                           + arrayType.soap11DimensionString() );
1228                continue;
1229             }
1230          }
1231 
1232          String value = null;
1233          if( multiValues != null )
1234          {
1235             String[] values = multiValues.get( attr.getName() );
1236             if( values != null )
1237                value = StringUtils.join( values, "," );
1238          }
1239          if( value == null )
1240             value = attr.getDefaultText();
1241          if( value == null )
1242             value = sampleDataForSimpleType( attr.getType() );
1243 
1244          xmlc.insertAttributeWithValue( attr.getName(), value );
1245       }
1246    }
1247 
1248    private void processSequence( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1249    {
1250       SchemaParticle[] spc = sp.getParticleChildren();
1251       for( int i = 0; i < spc.length; i++ )
1252       {
1253          // / <parent>maybestuff^</parent>
1254          processParticle( spc[i], xmlc, mixed );
1255          // <parent>maybestuff...morestuff^</parent>
1256          if( mixed && i < spc.length - 1 )
1257             xmlc.insertChars( pick( WORDS ) );
1258       }
1259    }
1260 
1261    private void processChoice( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1262    {
1263       SchemaParticle[] spc = sp.getParticleChildren();
1264       if( !_skipComments )
1265          xmlc.insertComment( "You have a CHOICE of the next " + String.valueOf( spc.length ) + " items at this level" );
1266 
1267       for( int i = 0; i < spc.length; i++ )
1268       {
1269          processParticle( spc[i], xmlc, mixed );
1270       }
1271    }
1272 
1273    private void processAll( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1274    {
1275       SchemaParticle[] spc = sp.getParticleChildren();
1276       if( !_skipComments )
1277          xmlc.insertComment( "You may enter the following " + String.valueOf( spc.length ) + " items in any order" );
1278 
1279       for( int i = 0; i < spc.length; i++ )
1280       {
1281          processParticle( spc[i], xmlc, mixed );
1282          if( mixed && i < spc.length - 1 )
1283             xmlc.insertChars( pick( WORDS ) );
1284       }
1285    }
1286 
1287    private void processWildCard( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1288    {
1289       if( !_skipComments )
1290          xmlc.insertComment( "You may enter ANY elements at this point" );
1291       // xmlc.insertElement("AnyElement");
1292    }
1293 
1294    /***
1295     * This method will get the base type for the schema type
1296     */
1297 
1298    private static QName getClosestName( SchemaType sType )
1299    {
1300       while( sType.getName() == null )
1301          sType = sType.getBaseType();
1302 
1303       return sType.getName();
1304    }
1305 
1306    private String printParticleType( int particleType )
1307    {
1308       StringBuffer returnParticleType = new StringBuffer();
1309       returnParticleType.append( "Schema Particle Type: " );
1310 
1311       switch( particleType )
1312       {
1313          case SchemaParticle.ALL:
1314             returnParticleType.append( "ALL\n" );
1315             break;
1316          case SchemaParticle.CHOICE:
1317             returnParticleType.append( "CHOICE\n" );
1318             break;
1319          case SchemaParticle.ELEMENT:
1320             returnParticleType.append( "ELEMENT\n" );
1321             break;
1322          case SchemaParticle.SEQUENCE:
1323             returnParticleType.append( "SEQUENCE\n" );
1324             break;
1325          case SchemaParticle.WILDCARD:
1326             returnParticleType.append( "WILDCARD\n" );
1327             break;
1328          default:
1329             returnParticleType.append( "Schema Particle Type Unknown" );
1330             break;
1331       }
1332 
1333       return returnParticleType.toString();
1334    }
1335 
1336    private ArrayList<SchemaType> _typeStack = new ArrayList<SchemaType>();
1337 
1338    public boolean isIgnoreOptional()
1339    {
1340       return ignoreOptional;
1341    }
1342 
1343    public void setIgnoreOptional( boolean ignoreOptional )
1344    {
1345       this.ignoreOptional = ignoreOptional;
1346    }
1347 
1348    private void addElementTypeAndRestricionsComment( SchemaLocalElement element, XmlCursor xmlc )
1349    {
1350 
1351       SchemaType type = element.getType();
1352       if( _typeComment && (type != null && type.isSimpleType()) )
1353       {
1354          String info = "";
1355 
1356          XmlAnySimpleType[] values = type.getEnumerationValues();
1357          if( values != null && values.length > 0 )
1358          {
1359             info = " - enumeration: [";
1360             for( int c = 0; c < values.length; c++ )
1361             {
1362                if( c > 0 )
1363                   info += ",";
1364 
1365                info += values[c].getStringValue();
1366             }
1367 
1368             info += "]";
1369          }
1370 
1371          if( type.isAnonymousType() )
1372             xmlc.insertComment( "anonymous type" + info );
1373          else
1374             xmlc.insertComment( "type: " + type.getName().getLocalPart() + info );
1375       }
1376    }
1377 
1378 }