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