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