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