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