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 	private String pickDigits( int digits )
505 	{
506 		StringBuffer sb = new StringBuffer();
507 		while( digits-- > 0 )
508 			sb.append( Integer.toString( pick( 10 ) ) );
509 		return sb.toString();
510 	}
511 
512 	private int pickLength( SchemaType sType )
513 	{
514 		XmlInteger length = ( XmlInteger )sType.getFacet( SchemaType.FACET_LENGTH );
515 		if( length != null )
516 			return length.getBigIntegerValue().intValue();
517 		XmlInteger min = ( XmlInteger )sType.getFacet( SchemaType.FACET_MIN_LENGTH );
518 		XmlInteger max = ( XmlInteger )sType.getFacet( SchemaType.FACET_MAX_LENGTH );
519 		int minInt, maxInt;
520 		if( min == null )
521 			minInt = 0;
522 		else
523 			minInt = min.getBigIntegerValue().intValue();
524 		if( max == null )
525 			maxInt = Integer.MAX_VALUE;
526 		else
527 			maxInt = max.getBigIntegerValue().intValue();
528 		// We try to keep the length of the array within reasonable limits,
529 		// at least 1 item and at most 3 if possible
530 		if( minInt == 0 && maxInt >= 1 )
531 			minInt = 1;
532 		if( maxInt > minInt + 2 )
533 			maxInt = minInt + 2;
534 		if( maxInt < minInt )
535 			maxInt = minInt;
536 		return minInt + pick( maxInt - minInt );
537 	}
538 
539 	/***
540 	 * Formats a given string to the required length, using the following
541 	 * operations: - append the source string to itself as necessary to pass the
542 	 * minLength; - truncate the result of previous step, if necessary, to keep
543 	 * it within minLength.
544 	 */
545 	private String formatToLength( String s, SchemaType sType )
546 	{
547 		String result = s;
548 		try
549 		{
550 			SimpleValue min = ( SimpleValue )sType.getFacet( SchemaType.FACET_LENGTH );
551 			if( min == null )
552 				min = ( SimpleValue )sType.getFacet( SchemaType.FACET_MIN_LENGTH );
553 			if( min != null )
554 			{
555 				int len = min.getIntValue();
556 				while( result.length() < len )
557 					result = result + result;
558 			}
559 			SimpleValue max = ( SimpleValue )sType.getFacet( SchemaType.FACET_LENGTH );
560 			if( max == null )
561 				max = ( SimpleValue )sType.getFacet( SchemaType.FACET_MAX_LENGTH );
562 			if( max != null )
563 			{
564 				int len = max.getIntValue();
565 				if( result.length() > len )
566 					result = result.substring( 0, len );
567 			}
568 		}
569 		catch( Exception e ) // intValue can be out of range
570 		{
571 		}
572 		return result;
573 	}
574 
575 	private String formatDecimal( String start, SchemaType sType )
576 	{
577 		BigDecimal result = new BigDecimal( start );
578 		XmlDecimal xmlD;
579 		xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
580 		BigDecimal min = xmlD != null ? xmlD.getBigDecimalValue() : null;
581 		xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
582 		BigDecimal max = xmlD != null ? xmlD.getBigDecimalValue() : null;
583 		boolean minInclusive = true, maxInclusive = true;
584 		xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
585 		if( xmlD != null )
586 		{
587 			BigDecimal minExcl = xmlD.getBigDecimalValue();
588 			if( min == null || min.compareTo( minExcl ) < 0 )
589 			{
590 				min = minExcl;
591 				minInclusive = false;
592 			}
593 		}
594 		xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
595 		if( xmlD != null )
596 		{
597 			BigDecimal maxExcl = xmlD.getBigDecimalValue();
598 			if( max == null || max.compareTo( maxExcl ) > 0 )
599 			{
600 				max = maxExcl;
601 				maxInclusive = false;
602 			}
603 		}
604 		xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_TOTAL_DIGITS );
605 		int totalDigits = -1;
606 		if( xmlD != null )
607 		{
608 			totalDigits = xmlD.getBigDecimalValue().intValue();
609 
610 			StringBuffer sb = new StringBuffer( totalDigits );
611 			for( int i = 0; i < totalDigits; i++ )
612 				sb.append( '9' );
613 			BigDecimal digitsLimit = new BigDecimal( sb.toString() );
614 			if( max != null && max.compareTo( digitsLimit ) > 0 )
615 			{
616 				max = digitsLimit;
617 				maxInclusive = true;
618 			}
619 			digitsLimit = digitsLimit.negate();
620 			if( min != null && min.compareTo( digitsLimit ) < 0 )
621 			{
622 				min = digitsLimit;
623 				minInclusive = true;
624 			}
625 		}
626 
627 		int sigMin = min == null ? 1 : result.compareTo( min );
628 		int sigMax = max == null ? -1 : result.compareTo( max );
629 		boolean minOk = sigMin > 0 || sigMin == 0 && minInclusive;
630 		boolean maxOk = sigMax < 0 || sigMax == 0 && maxInclusive;
631 
632 		// Compute the minimum increment
633 		xmlD = ( XmlDecimal )sType.getFacet( SchemaType.FACET_FRACTION_DIGITS );
634 		int fractionDigits = -1;
635 		BigDecimal increment;
636 		if( xmlD == null )
637 			increment = new BigDecimal( 1 );
638 		else
639 		{
640 			fractionDigits = xmlD.getBigDecimalValue().intValue();
641 			if( fractionDigits > 0 )
642 			{
643 				StringBuffer sb = new StringBuffer( "0." );
644 				for( int i = 1; i < fractionDigits; i++ )
645 					sb.append( '0' );
646 				sb.append( '1' );
647 				increment = new BigDecimal( sb.toString() );
648 			}
649 			else
650 				increment = new BigDecimal( 1 );
651 		}
652 
653 		if( minOk && maxOk )
654 		{
655 			// OK
656 		}
657 		else if( minOk && !maxOk )
658 		{
659 			// TOO BIG
660 			if( maxInclusive )
661 				result = max;
662 			else
663 				result = max.subtract( increment );
664 		}
665 		else if( !minOk && maxOk )
666 		{
667 			// TOO SMALL
668 			if( minInclusive )
669 				result = min;
670 			else
671 				result = min.add( increment );
672 		}
673 		else
674 		{
675 			// MIN > MAX!!
676 		}
677 
678 		// We have the number
679 		// Adjust the scale according to the totalDigits and fractionDigits
680 		int digits = 0;
681 		BigDecimal ONE = new BigDecimal( BigInteger.ONE );
682 		for( BigDecimal n = result; n.abs().compareTo( ONE ) >= 0; digits++ )
683 			n = n.movePointLeft( 1 );
684 
685 		if( fractionDigits > 0 )
686 			if( totalDigits >= 0 )
687 				result.setScale( Math.max( fractionDigits, totalDigits - digits ) );
688 			else
689 				result.setScale( fractionDigits );
690 		else if( fractionDigits == 0 )
691 			result.setScale( 0 );
692 
693 		return result.toString();
694 	}
695 
696 	private String formatDuration( SchemaType sType )
697 	{
698 		XmlDuration d = ( XmlDuration )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
699 		GDuration minInclusive = null;
700 		if( d != null )
701 			minInclusive = d.getGDurationValue();
702 
703 		d = ( XmlDuration )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
704 		GDuration maxInclusive = null;
705 		if( d != null )
706 			maxInclusive = d.getGDurationValue();
707 
708 		d = ( XmlDuration )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
709 		GDuration minExclusive = null;
710 		if( d != null )
711 			minExclusive = d.getGDurationValue();
712 
713 		d = ( XmlDuration )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
714 		GDuration maxExclusive = null;
715 		if( d != null )
716 			maxExclusive = d.getGDurationValue();
717 
718 		GDurationBuilder gdurb = new GDurationBuilder();
719 		BigInteger min, max;
720 
721 		gdurb.setSecond( pick( 800000 ) );
722 		gdurb.setMonth( pick( 20 ) );
723 
724 		// Years
725 		// Months
726 		// Days
727 		// Hours
728 		// Minutes
729 		// Seconds
730 		// Fractions
731 		if( minInclusive != null )
732 		{
733 			if( gdurb.getYear() < minInclusive.getYear() )
734 				gdurb.setYear( minInclusive.getYear() );
735 			if( gdurb.getMonth() < minInclusive.getMonth() )
736 				gdurb.setMonth( minInclusive.getMonth() );
737 			if( gdurb.getDay() < minInclusive.getDay() )
738 				gdurb.setDay( minInclusive.getDay() );
739 			if( gdurb.getHour() < minInclusive.getHour() )
740 				gdurb.setHour( minInclusive.getHour() );
741 			if( gdurb.getMinute() < minInclusive.getMinute() )
742 				gdurb.setMinute( minInclusive.getMinute() );
743 			if( gdurb.getSecond() < minInclusive.getSecond() )
744 				gdurb.setSecond( minInclusive.getSecond() );
745 			if( gdurb.getFraction().compareTo( minInclusive.getFraction() ) < 0 )
746 				gdurb.setFraction( minInclusive.getFraction() );
747 		}
748 
749 		if( maxInclusive != null )
750 		{
751 			if( gdurb.getYear() > maxInclusive.getYear() )
752 				gdurb.setYear( maxInclusive.getYear() );
753 			if( gdurb.getMonth() > maxInclusive.getMonth() )
754 				gdurb.setMonth( maxInclusive.getMonth() );
755 			if( gdurb.getDay() > maxInclusive.getDay() )
756 				gdurb.setDay( maxInclusive.getDay() );
757 			if( gdurb.getHour() > maxInclusive.getHour() )
758 				gdurb.setHour( maxInclusive.getHour() );
759 			if( gdurb.getMinute() > maxInclusive.getMinute() )
760 				gdurb.setMinute( maxInclusive.getMinute() );
761 			if( gdurb.getSecond() > maxInclusive.getSecond() )
762 				gdurb.setSecond( maxInclusive.getSecond() );
763 			if( gdurb.getFraction().compareTo( maxInclusive.getFraction() ) > 0 )
764 				gdurb.setFraction( maxInclusive.getFraction() );
765 		}
766 
767 		if( minExclusive != null )
768 		{
769 			if( gdurb.getYear() <= minExclusive.getYear() )
770 				gdurb.setYear( minExclusive.getYear() + 1 );
771 			if( gdurb.getMonth() <= minExclusive.getMonth() )
772 				gdurb.setMonth( minExclusive.getMonth() + 1 );
773 			if( gdurb.getDay() <= minExclusive.getDay() )
774 				gdurb.setDay( minExclusive.getDay() + 1 );
775 			if( gdurb.getHour() <= minExclusive.getHour() )
776 				gdurb.setHour( minExclusive.getHour() + 1 );
777 			if( gdurb.getMinute() <= minExclusive.getMinute() )
778 				gdurb.setMinute( minExclusive.getMinute() + 1 );
779 			if( gdurb.getSecond() <= minExclusive.getSecond() )
780 				gdurb.setSecond( minExclusive.getSecond() + 1 );
781 			if( gdurb.getFraction().compareTo( minExclusive.getFraction() ) <= 0 )
782 				gdurb.setFraction( minExclusive.getFraction().add( new BigDecimal( 0.001 ) ) );
783 		}
784 
785 		if( maxExclusive != null )
786 		{
787 			if( gdurb.getYear() > maxExclusive.getYear() )
788 				gdurb.setYear( maxExclusive.getYear() );
789 			if( gdurb.getMonth() > maxExclusive.getMonth() )
790 				gdurb.setMonth( maxExclusive.getMonth() );
791 			if( gdurb.getDay() > maxExclusive.getDay() )
792 				gdurb.setDay( maxExclusive.getDay() );
793 			if( gdurb.getHour() > maxExclusive.getHour() )
794 				gdurb.setHour( maxExclusive.getHour() );
795 			if( gdurb.getMinute() > maxExclusive.getMinute() )
796 				gdurb.setMinute( maxExclusive.getMinute() );
797 			if( gdurb.getSecond() > maxExclusive.getSecond() )
798 				gdurb.setSecond( maxExclusive.getSecond() );
799 			if( gdurb.getFraction().compareTo( maxExclusive.getFraction() ) > 0 )
800 				gdurb.setFraction( maxExclusive.getFraction() );
801 		}
802 
803 		gdurb.normalize();
804 		return gdurb.toString();
805 	}
806 
807 	private String formatDate( SchemaType sType )
808 	{
809 		GDateBuilder gdateb = new GDateBuilder( new Date( 1000L * pick( 365 * 24 * 60 * 60 ) + ( 30L + pick( 20 ) ) * 365
810 				* 24 * 60 * 60 * 1000 ) );
811 		GDate min = null, max = null;
812 		GDate temp;
813 
814 		// Find the min and the max according to the type
815 		switch( sType.getPrimitiveType().getBuiltinTypeCode() )
816 		{
817 		case SchemaType.BTC_DATE_TIME :
818 		{
819 			XmlDateTime x = ( XmlDateTime )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
820 			if( x != null )
821 				min = x.getGDateValue();
822 			x = ( XmlDateTime )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 = ( XmlDateTime )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
828 			if( x != null )
829 				max = x.getGDateValue();
830 			x = ( XmlDateTime )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_TIME :
837 		{
838 			XmlTime x = ( XmlTime )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
839 			if( x != null )
840 				min = x.getGDateValue();
841 			x = ( XmlTime )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 = ( XmlTime )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
847 			if( x != null )
848 				max = x.getGDateValue();
849 			x = ( XmlTime )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_DATE :
856 		{
857 			XmlDate x = ( XmlDate )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
858 			if( x != null )
859 				min = x.getGDateValue();
860 			x = ( XmlDate )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 = ( XmlDate )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
866 			if( x != null )
867 				max = x.getGDateValue();
868 			x = ( XmlDate )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_MONTH :
875 		{
876 			XmlGYearMonth x = ( XmlGYearMonth )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
877 			if( x != null )
878 				min = x.getGDateValue();
879 			x = ( XmlGYearMonth )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 = ( XmlGYearMonth )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
885 			if( x != null )
886 				max = x.getGDateValue();
887 			x = ( XmlGYearMonth )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_YEAR :
894 		{
895 			XmlGYear x = ( XmlGYear )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
896 			if( x != null )
897 				min = x.getGDateValue();
898 			x = ( XmlGYear )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 = ( XmlGYear )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
904 			if( x != null )
905 				max = x.getGDateValue();
906 			x = ( XmlGYear )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_MONTH_DAY :
913 		{
914 			XmlGMonthDay x = ( XmlGMonthDay )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
915 			if( x != null )
916 				min = x.getGDateValue();
917 			x = ( XmlGMonthDay )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 = ( XmlGMonthDay )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
923 			if( x != null )
924 				max = x.getGDateValue();
925 			x = ( XmlGMonthDay )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_DAY :
932 		{
933 			XmlGDay x = ( XmlGDay )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
934 			if( x != null )
935 				min = x.getGDateValue();
936 			x = ( XmlGDay )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 = ( XmlGDay )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
942 			if( x != null )
943 				max = x.getGDateValue();
944 			x = ( XmlGDay )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 		case SchemaType.BTC_G_MONTH :
951 		{
952 			XmlGMonth x = ( XmlGMonth )sType.getFacet( SchemaType.FACET_MIN_INCLUSIVE );
953 			if( x != null )
954 				min = x.getGDateValue();
955 			x = ( XmlGMonth )sType.getFacet( SchemaType.FACET_MIN_EXCLUSIVE );
956 			if( x != null )
957 				if( min == null || min.compareToGDate( x.getGDateValue() ) <= 0 )
958 					min = x.getGDateValue();
959 
960 			x = ( XmlGMonth )sType.getFacet( SchemaType.FACET_MAX_INCLUSIVE );
961 			if( x != null )
962 				max = x.getGDateValue();
963 			x = ( XmlGMonth )sType.getFacet( SchemaType.FACET_MAX_EXCLUSIVE );
964 			if( x != null )
965 				if( max == null || max.compareToGDate( x.getGDateValue() ) >= 0 )
966 					max = x.getGDateValue();
967 			break;
968 		}
969 		}
970 
971 		if( min != null && max == null )
972 		{
973 			if( min.compareToGDate( gdateb ) >= 0 )
974 			{
975 				// Reset the date to min + (1-8) hours
976 				Calendar c = gdateb.getCalendar();
977 				c.add( Calendar.HOUR_OF_DAY, pick( 8 ) );
978 				gdateb = new GDateBuilder( c );
979 			}
980 		}
981 		else if( min == null && max != null )
982 		{
983 			if( max.compareToGDate( gdateb ) <= 0 )
984 			{
985 				// Reset the date to max - (1-8) hours
986 				Calendar c = gdateb.getCalendar();
987 				c.add( Calendar.HOUR_OF_DAY, 0 - pick( 8 ) );
988 				gdateb = new GDateBuilder( c );
989 			}
990 		}
991 		else if( min != null && max != null )
992 		{
993 			if( min.compareToGDate( gdateb ) >= 0 || max.compareToGDate( gdateb ) <= 0 )
994 			{
995 				// Find a date between the two
996 				Calendar c = min.getCalendar();
997 				Calendar cmax = max.getCalendar();
998 				c.add( Calendar.HOUR_OF_DAY, 1 );
999 				if( c.after( cmax ) )
1000 				{
1001 					c.add( Calendar.HOUR_OF_DAY, -1 );
1002 					c.add( Calendar.MINUTE, 1 );
1003 					if( c.after( cmax ) )
1004 					{
1005 						c.add( Calendar.MINUTE, -1 );
1006 						c.add( Calendar.SECOND, 1 );
1007 						if( c.after( cmax ) )
1008 						{
1009 							c.add( Calendar.SECOND, -1 );
1010 							c.add( Calendar.MILLISECOND, 1 );
1011 							if( c.after( cmax ) )
1012 								c.add( Calendar.MILLISECOND, -1 );
1013 						}
1014 					}
1015 				}
1016 				gdateb = new GDateBuilder( c );
1017 			}
1018 		}
1019 
1020 		gdateb.setBuiltinTypeCode( sType.getPrimitiveType().getBuiltinTypeCode() );
1021 		if( pick( 2 ) == 0 )
1022 			gdateb.clearTimeZone();
1023 		return gdateb.toString();
1024 	}
1025 
1026 	private SchemaType closestBuiltin( SchemaType sType )
1027 	{
1028 		while( !sType.isBuiltinType() )
1029 			sType = sType.getBaseType();
1030 		return sType;
1031 	}
1032 
1033 	/***
1034 	 * Cracks a combined QName of the form URL:localname
1035 	 */
1036 	public static QName crackQName( String qName )
1037 	{
1038 		String ns;
1039 		String name;
1040 
1041 		int index = qName.lastIndexOf( ':' );
1042 		if( index >= 0 )
1043 		{
1044 			ns = qName.substring( 0, index );
1045 			name = qName.substring( index + 1 );
1046 		}
1047 		else
1048 		{
1049 			ns = "";
1050 			name = qName;
1051 		}
1052 
1053 		return new QName( ns, name );
1054 	}
1055 
1056 	/***
1057 	 * Cursor position: Before this call: <outer><foo/>^</outer> (cursor at the
1058 	 * ^) After this call: <<outer><foo/><bar/>som text<etc/>^</outer>
1059 	 */
1060 	private void processParticle( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1061 	{
1062 		int loop = determineMinMaxForSample( sp, xmlc );
1063 
1064 		while( loop-- > 0 )
1065 		{
1066 			switch( sp.getParticleType() )
1067 			{
1068 			case ( SchemaParticle.ELEMENT ) :
1069 				processElement( sp, xmlc, mixed );
1070 				break;
1071 			case ( SchemaParticle.SEQUENCE ) :
1072 				processSequence( sp, xmlc, mixed );
1073 				break;
1074 			case ( SchemaParticle.CHOICE ) :
1075 				processChoice( sp, xmlc, mixed );
1076 				break;
1077 			case ( SchemaParticle.ALL ) :
1078 				processAll( sp, xmlc, mixed );
1079 				break;
1080 			case ( SchemaParticle.WILDCARD ) :
1081 				processWildCard( sp, xmlc, mixed );
1082 				break;
1083 			default :
1084 				// throw new Exception("No Match on Schema Particle Type: " +
1085 				// String.valueOf(sp.getParticleType()));
1086 			}
1087 		}
1088 	}
1089 
1090 	private int determineMinMaxForSample( SchemaParticle sp, XmlCursor xmlc )
1091 	{
1092 		int minOccurs = sp.getIntMinOccurs();
1093 		int maxOccurs = sp.getIntMaxOccurs();
1094 
1095 		if( minOccurs == maxOccurs )
1096 			return minOccurs;
1097 
1098 		if( minOccurs == 0 && ignoreOptional )
1099 			return 0;
1100 
1101 		int result = minOccurs;
1102 		if( result == 0 )
1103 			result = 1;
1104 
1105 		if( sp.getParticleType() != SchemaParticle.ELEMENT )
1106 			return result;
1107 
1108 		// it probably only makes sense to put comments in front of individual
1109 		// elements that repeat
1110 
1111 		if( !_skipComments )
1112 		{
1113 			if( sp.getMaxOccurs() == null )
1114 			{
1115 				// xmlc.insertComment("The next " + getItemNameOrType(sp, xmlc) + "
1116 				// may
1117 				// be repeated " + minOccurs + " or more times");
1118 				if( minOccurs == 0 )
1119 					xmlc.insertComment( "Zero or more repetitions:" );
1120 				else
1121 					xmlc.insertComment( minOccurs + " or more repetitions:" );
1122 			}
1123 			else if( sp.getIntMaxOccurs() > 1 )
1124 			{
1125 				xmlc.insertComment( minOccurs + " to " + String.valueOf( sp.getMaxOccurs() ) + " repetitions:" );
1126 			}
1127 			else
1128 			{
1129 				xmlc.insertComment( "Optional:" );
1130 			}
1131 		}
1132 
1133 		return result;
1134 	}
1135 
1136 	/*
1137 	 * Return a name for the element or the particle type to use in the comment
1138 	 * for minoccurs, max occurs
1139 	 */
1140 	private String getItemNameOrType( SchemaParticle sp, XmlCursor xmlc )
1141 	{
1142 		String elementOrTypeName = null;
1143 		if( sp.getParticleType() == SchemaParticle.ELEMENT )
1144 		{
1145 			elementOrTypeName = "Element (" + sp.getName().getLocalPart() + ")";
1146 		}
1147 		else
1148 		{
1149 			elementOrTypeName = printParticleType( sp.getParticleType() );
1150 		}
1151 		return elementOrTypeName;
1152 	}
1153 
1154 	private void processElement( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1155 	{
1156 		// cast as schema local element
1157 		SchemaLocalElement element = ( SchemaLocalElement )sp;
1158 
1159 		// Add comment about type
1160 		addElementTypeAndRestricionsComment( element, xmlc );
1161 
1162 		// / ^ -> <elemenname></elem>^
1163 		if( _soapEnc )
1164 			xmlc.insertElement( element.getName().getLocalPart() ); // soap
1165 		// encoded?
1166 		// drop
1167 		// namespaces.
1168 		else
1169 			xmlc.insertElement( element.getName().getLocalPart(), element.getName().getNamespaceURI() );
1170 		// / -> <elem>^</elem>
1171 		// processAttributes( sp.getType(), xmlc );
1172 
1173 		xmlc.toPrevToken();
1174 		// -> <elem>stuff^</elem>
1175 
1176 		String[] values = null;
1177 		if( multiValues != null )
1178 			values = multiValues.get( element.getName() );
1179 		if( values != null )
1180 			xmlc.insertChars( StringUtils.join( values, "," ) );
1181 		else if( sp.isDefault() )
1182 			xmlc.insertChars( sp.getDefaultText() );
1183 		else
1184 			createSampleForType( element.getType(), xmlc );
1185 		// -> <elem>stuff</elem>^
1186 		xmlc.toNextToken();
1187 	}
1188 
1189 	private void moveToken( int numToMove, XmlCursor xmlc )
1190 	{
1191 		for( int i = 0; i < Math.abs( numToMove ); i++ )
1192 		{
1193 			if( numToMove < 0 )
1194 			{
1195 				xmlc.toPrevToken();
1196 			}
1197 			else
1198 			{
1199 				xmlc.toNextToken();
1200 			}
1201 		}
1202 	}
1203 
1204 	private static final String formatQName( XmlCursor xmlc, QName qName )
1205 	{
1206 		XmlCursor parent = xmlc.newCursor();
1207 		parent.toParent();
1208 		String prefix = parent.prefixForNamespace( qName.getNamespaceURI() );
1209 		parent.dispose();
1210 		String name;
1211 		if( prefix == null || prefix.length() == 0 )
1212 			name = qName.getLocalPart();
1213 		else
1214 			name = prefix + ":" + qName.getLocalPart();
1215 		return name;
1216 	}
1217 
1218 	private static final QName HREF = new QName( "href" );
1219 	private static final QName ID = new QName( "id" );
1220 	public static final QName XSI_TYPE = new QName( "http://www.w3.org/2001/XMLSchema-instance", "type" );
1221 	public static final QName ENC_ARRAYTYPE = new QName( "http://schemas.xmlsoap.org/soap/encoding/", "arrayType" );
1222 	private static final QName ENC_OFFSET = new QName( "http://schemas.xmlsoap.org/soap/encoding/", "offset" );
1223 
1224 	public static final Set<QName> SKIPPED_SOAP_ATTRS = new HashSet<QName>( Arrays.asList( new QName[] { HREF, ID,
1225 			ENC_OFFSET } ) );
1226 
1227 	private void processAttributes( SchemaType stype, XmlCursor xmlc )
1228 	{
1229 		if( _soapEnc )
1230 		{
1231 			QName typeName = stype.getName();
1232 			if( typeName != null )
1233 			{
1234 				xmlc.insertAttributeWithValue( XSI_TYPE, formatQName( xmlc, typeName ) );
1235 			}
1236 		}
1237 
1238 		SchemaProperty[] attrProps = stype.getAttributeProperties();
1239 		for( int i = 0; i < attrProps.length; i++ )
1240 		{
1241 			SchemaProperty attr = attrProps[i];
1242 
1243 			if( attr.getName().equals( new QName( "http://www.w3.org/2005/05/xmlmime", "contentType" ) ) )
1244 			{
1245 				xmlc.insertAttributeWithValue( attr.getName(), "application/?" );
1246 				continue;
1247 			}
1248 
1249 			if( _soapEnc )
1250 			{
1251 				if( SKIPPED_SOAP_ATTRS.contains( attr.getName() ) )
1252 					continue;
1253 				if( ENC_ARRAYTYPE.equals( attr.getName() ) )
1254 				{
1255 					SOAPArrayType arrayType = ( ( SchemaWSDLArrayType )stype.getAttributeModel().getAttribute(
1256 							attr.getName() ) ).getWSDLArrayType();
1257 					if( arrayType != null )
1258 						xmlc.insertAttributeWithValue( attr.getName(), formatQName( xmlc, arrayType.getQName() )
1259 								+ arrayType.soap11DimensionString() );
1260 					continue;
1261 				}
1262 			}
1263 
1264 			String value = null;
1265 			if( multiValues != null )
1266 			{
1267 				String[] values = multiValues.get( attr.getName() );
1268 				if( values != null )
1269 					value = StringUtils.join( values, "," );
1270 			}
1271 			if( value == null )
1272 				value = attr.getDefaultText();
1273 			if( value == null )
1274 				value = sampleDataForSimpleType( attr.getType() );
1275 
1276 			xmlc.insertAttributeWithValue( attr.getName(), value );
1277 		}
1278 	}
1279 
1280 	private void processSequence( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1281 	{
1282 		SchemaParticle[] spc = sp.getParticleChildren();
1283 		for( int i = 0; i < spc.length; i++ )
1284 		{
1285 			// / <parent>maybestuff^</parent>
1286 			processParticle( spc[i], xmlc, mixed );
1287 			// <parent>maybestuff...morestuff^</parent>
1288 			if( mixed && i < spc.length - 1 )
1289 				xmlc.insertChars( pick( WORDS ) );
1290 		}
1291 	}
1292 
1293 	private void processChoice( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1294 	{
1295 		SchemaParticle[] spc = sp.getParticleChildren();
1296 		if( !_skipComments )
1297 			xmlc.insertComment( "You have a CHOICE of the next " + String.valueOf( spc.length ) + " items at this level" );
1298 
1299 		for( int i = 0; i < spc.length; i++ )
1300 		{
1301 			processParticle( spc[i], xmlc, mixed );
1302 		}
1303 	}
1304 
1305 	private void processAll( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1306 	{
1307 		SchemaParticle[] spc = sp.getParticleChildren();
1308 		if( !_skipComments )
1309 			xmlc.insertComment( "You may enter the following " + String.valueOf( spc.length ) + " items in any order" );
1310 
1311 		for( int i = 0; i < spc.length; i++ )
1312 		{
1313 			processParticle( spc[i], xmlc, mixed );
1314 			if( mixed && i < spc.length - 1 )
1315 				xmlc.insertChars( pick( WORDS ) );
1316 		}
1317 	}
1318 
1319 	private void processWildCard( SchemaParticle sp, XmlCursor xmlc, boolean mixed )
1320 	{
1321 		if( !_skipComments )
1322 			xmlc.insertComment( "You may enter ANY elements at this point" );
1323 		// xmlc.insertElement("AnyElement");
1324 	}
1325 
1326 	/***
1327 	 * This method will get the base type for the schema type
1328 	 */
1329 
1330 	private static QName getClosestName( SchemaType sType )
1331 	{
1332 		while( sType.getName() == null )
1333 			sType = sType.getBaseType();
1334 
1335 		return sType.getName();
1336 	}
1337 
1338 	private String printParticleType( int particleType )
1339 	{
1340 		StringBuffer returnParticleType = new StringBuffer();
1341 		returnParticleType.append( "Schema Particle Type: " );
1342 
1343 		switch( particleType )
1344 		{
1345 		case SchemaParticle.ALL :
1346 			returnParticleType.append( "ALL\n" );
1347 			break;
1348 		case SchemaParticle.CHOICE :
1349 			returnParticleType.append( "CHOICE\n" );
1350 			break;
1351 		case SchemaParticle.ELEMENT :
1352 			returnParticleType.append( "ELEMENT\n" );
1353 			break;
1354 		case SchemaParticle.SEQUENCE :
1355 			returnParticleType.append( "SEQUENCE\n" );
1356 			break;
1357 		case SchemaParticle.WILDCARD :
1358 			returnParticleType.append( "WILDCARD\n" );
1359 			break;
1360 		default :
1361 			returnParticleType.append( "Schema Particle Type Unknown" );
1362 			break;
1363 		}
1364 
1365 		return returnParticleType.toString();
1366 	}
1367 
1368 	private ArrayList<SchemaType> _typeStack = new ArrayList<SchemaType>();
1369 
1370 	public boolean isIgnoreOptional()
1371 	{
1372 		return ignoreOptional;
1373 	}
1374 
1375 	public void setIgnoreOptional( boolean ignoreOptional )
1376 	{
1377 		this.ignoreOptional = ignoreOptional;
1378 	}
1379 
1380 	private void addElementTypeAndRestricionsComment( SchemaLocalElement element, XmlCursor xmlc )
1381 	{
1382 
1383 		SchemaType type = element.getType();
1384 		if( _typeComment && ( type != null && type.isSimpleType() ) )
1385 		{
1386 			String info = "";
1387 
1388 			XmlAnySimpleType[] values = type.getEnumerationValues();
1389 			if( values != null && values.length > 0 )
1390 			{
1391 				info = " - enumeration: [";
1392 				for( int c = 0; c < values.length; c++ )
1393 				{
1394 					if( c > 0 )
1395 						info += ",";
1396 
1397 					info += values[c].getStringValue();
1398 				}
1399 
1400 				info += "]";
1401 			}
1402 
1403 			if( type.isAnonymousType() )
1404 				xmlc.insertComment( "anonymous type" + info );
1405 			else
1406 				xmlc.insertComment( "type: " + type.getName().getLocalPart() + info );
1407 		}
1408 	}
1409 
1410 }