View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.support.xsd;
14  
15  import java.io.File;
16  import java.io.IOException;
17  import java.net.MalformedURLException;
18  import java.net.URL;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  import java.util.StringTokenizer;
27  
28  import javax.xml.namespace.QName;
29  
30  import org.apache.log4j.Logger;
31  import org.apache.xmlbeans.SchemaAnnotation;
32  import org.apache.xmlbeans.SchemaLocalElement;
33  import org.apache.xmlbeans.SchemaParticle;
34  import org.apache.xmlbeans.SchemaType;
35  import org.apache.xmlbeans.SchemaTypeLoader;
36  import org.apache.xmlbeans.SchemaTypeSystem;
37  import org.apache.xmlbeans.SimpleValue;
38  import org.apache.xmlbeans.XmlAnySimpleType;
39  import org.apache.xmlbeans.XmlBase64Binary;
40  import org.apache.xmlbeans.XmlBeans;
41  import org.apache.xmlbeans.XmlCursor;
42  import org.apache.xmlbeans.XmlException;
43  import org.apache.xmlbeans.XmlHexBinary;
44  import org.apache.xmlbeans.XmlObject;
45  import org.apache.xmlbeans.XmlOptions;
46  import org.w3c.dom.Document;
47  import org.w3c.dom.Element;
48  import org.w3c.dom.NamedNodeMap;
49  import org.w3c.dom.Node;
50  
51  import com.eviware.soapui.SoapUI;
52  import com.eviware.soapui.impl.wsdl.support.Constants;
53  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
54  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlLoader;
55  import com.eviware.soapui.model.settings.SettingsListener;
56  import com.eviware.soapui.settings.WsdlSettings;
57  import com.eviware.soapui.support.Tools;
58  
59  /***
60   * XML-Schema related tools
61   * 
62   * @author Ole.Matzura
63   */
64  
65  public class SchemaUtils
66  {
67     private final static Logger log = Logger.getLogger( SchemaUtils.class );
68  	private static Map<String,XmlObject> defaultSchemas = new HashMap<String,XmlObject>();
69  	
70     static
71     {
72     	initDefaultSchemas();
73     	
74     	SoapUI.getSettings().addSettingsListener( new SettingsListener() {
75  
76  			public void settingChanged( String name, String newValue, String oldValue )
77  			{
78  				if( name.equals( WsdlSettings.SCHEMA_DIRECTORY ))
79  				{
80  					log.info( "Reloading default schemas.." );
81  					initDefaultSchemas();
82  				}
83  			}});
84     }
85  
86  	public static void initDefaultSchemas()
87  	{
88  		ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
89     	Thread.currentThread().setContextClassLoader( SoapUI.class.getClassLoader() );
90     	
91     	try
92  		{
93     		defaultSchemas.clear();
94     		loadDefaultSchema( SoapUI.class.getResource("/xop.xsd") );
95     		loadDefaultSchema( SoapUI.class.getResource("/XMLSchema.xsd") );
96     		loadDefaultSchema( SoapUI.class.getResource("/xml.xsd") );
97     		loadDefaultSchema( SoapUI.class.getResource("/swaref.xsd") );
98     		loadDefaultSchema( SoapUI.class.getResource("/xmime200505.xsd") );
99     		loadDefaultSchema( SoapUI.class.getResource("/xmime200411.xsd") );
100    		
101    		String schemaDirectory = SoapUI.getSchemaDirectory();
102    		if( schemaDirectory != null && schemaDirectory.trim().length() > 0 )
103    			loadSchemaDirectory( schemaDirectory );
104 		}
105 		catch (Exception e)
106 		{
107 			SoapUI.logError( e );
108 		}
109 		finally
110    	{
111    		Thread.currentThread().setContextClassLoader( contextClassLoader );
112    	}
113 	}
114 
115 	private static void loadSchemaDirectory( String schemaDirectory ) throws IOException, MalformedURLException
116 	{
117 		File dir = new File( schemaDirectory );
118 		if( dir.exists() && dir.isDirectory() )
119 		{
120 			String[] xsdFiles = dir.list();
121 			int cnt = 0;
122 			
123 			if( xsdFiles != null && xsdFiles.length > 0 )
124 			{
125 				for( int c = 0; c < xsdFiles.length; c++ )
126 				{
127 					try
128 					{
129 						String xsdFile = xsdFiles[c];
130 						if( xsdFile.endsWith( ".xsd" ))
131 						{
132 							String filename = schemaDirectory + File.separator + xsdFile;
133 							loadDefaultSchema( new URL( "file:" + filename ) );
134 							cnt++;
135 						}
136 					}
137 					catch( Exception e )
138 					{
139 						SoapUI.logError( e );
140 					}
141 				}
142 			}
143 			
144 			if( cnt == 0 )
145 				log.warn( "Missing schema files in  schemaDirectory [" + schemaDirectory + "]" );
146 		}
147 		else log.warn( "Failed to open schemaDirectory [" + schemaDirectory + "]" );
148 	}
149    
150    private static void loadDefaultSchema( URL url ) throws XmlException, IOException
151    {
152    	XmlObject xmlObject = XmlObject.Factory.parse( url );
153 		String targetNamespace = getTargetNamespace( xmlObject );
154 		
155 		if( defaultSchemas.containsKey( targetNamespace  ))
156 			log.warn( "Overriding schema for targetNamespace " + targetNamespace );
157 		
158 		defaultSchemas.put(  targetNamespace, xmlObject );
159 		
160 		log.info( "Added default schema from " + url.getPath() + " with targetNamespace " + targetNamespace );
161    }
162    
163    public static SchemaTypeLoader loadSchemaTypes(String wsdlUrl, SoapVersion soapVersion, WsdlLoader loader ) throws SchemaException
164    {
165    	ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
166    	Thread.currentThread().setContextClassLoader( SoapUI.class.getClassLoader() );
167    	
168    	try
169 		{
170 			log.info("Loading schema types from [" + wsdlUrl + "]");
171 			ArrayList<XmlObject> schemas = new ArrayList<XmlObject>(getSchemas(
172 					wsdlUrl, loader).values());
173 
174 			return buildSchemaTypes(schemas, soapVersion);
175 		}
176 		catch (Exception e)
177 		{
178 			throw new SchemaException( "Error loading schema types", e );
179 		}
180 		finally
181    	{
182    		Thread.currentThread().setContextClassLoader( contextClassLoader );
183    	}
184    }
185 
186    public static SchemaTypeLoader buildSchemaTypes(List<XmlObject> schemas, SoapVersion soapVersion) throws SchemaException
187    {
188       XmlOptions options = new XmlOptions();
189       options.setCompileNoValidation();
190       options.setCompileNoPvrRule();
191       options.setCompileDownloadUrls();
192       options.setCompileNoUpaRule();
193       options.setValidateTreatLaxAsSkip();
194       
195       if( !SoapUI.getSettings().getBoolean( WsdlSettings.STRICT_SCHEMA_TYPES ))
196       {
197          Set<String> mdefNamespaces = new HashSet<String>();
198 
199          for (XmlObject xObj: schemas) 
200          {
201          	mdefNamespaces.add( getTargetNamespace( xObj ) );
202          }  
203          
204          options.setCompileMdefNamespaces(mdefNamespaces);
205       }
206       
207       ArrayList errorList = new ArrayList();
208       options.setErrorListener( errorList );
209 
210       XmlCursor cursor = null;
211       
212       try
213 		{
214       	// remove imports
215 			for( int c = 0; c < schemas.size(); c++ )
216 			{
217 				XmlObject s = schemas.get( c );
218 				
219 				Map map = new HashMap();
220 				cursor = s.newCursor();
221 				cursor.toStartDoc(); 
222 				if( toNextContainer(cursor))
223 					cursor.getAllNamespaces( map );
224 				else
225 					log.warn( "Can not get namespaces for " + s );
226 				
227 				String tns = getTargetNamespace(s);
228 				
229 				log.info( "schema for [" + tns + "] contained [" + map.toString() + "] namespaces" );
230 
231 				
232 				if( defaultSchemas.containsKey( tns ) ||
233 					 tns.equals( getTargetNamespace(soapVersion.getSoapEncodingSchema()) ) ||
234 					 tns.equals( getTargetNamespace(soapVersion.getSoapEnvelopeSchema() )))
235 				{
236 					schemas.remove( c );
237 					c--;
238 				}
239 				else
240 				{
241 					removeImports(s);
242 				}
243 				
244 				cursor.dispose();
245 				cursor = null;
246 			}
247 
248       	schemas.add( soapVersion.getSoapEncodingSchema());
249       	schemas.add( soapVersion.getSoapEnvelopeSchema());
250       	schemas.addAll( defaultSchemas.values() );
251       	
252       	SchemaTypeSystem sts = XmlBeans.compileXsd(
253       			schemas.toArray(new XmlObject[schemas.size()]), XmlBeans.getBuiltinTypeSystem(), options);
254       	return XmlBeans.typeLoaderUnion(new SchemaTypeLoader[] { sts, XmlBeans.getBuiltinTypeSystem() });
255 		}
256 		catch (Exception e)
257 		{
258 			SoapUI.logError( e );
259 			throw new SchemaException( e, errorList );
260 		}
261 		finally
262 		{
263 			for( int c = 0; c < errorList.size(); c++ )
264 			{
265 				log.warn( "Error: " + errorList.get( c ));
266 			}
267 			
268 			if( cursor != null )
269 				cursor.dispose();
270 		}
271    }
272 
273 	public static boolean toNextContainer(XmlCursor cursor)
274 	{
275 		while( !cursor.isContainer() && !cursor.isEnddoc() )
276 			cursor.toNextToken();
277 		
278 		return cursor.isContainer();
279 	}
280 
281 	public static String getTargetNamespace(XmlObject s)
282 	{
283 		return ((Document)s.getDomNode()).getDocumentElement().getAttribute( "targetNamespace" );
284 	}
285    
286    public static Map<String,XmlObject> getSchemas( String wsdlUrl, WsdlLoader loader ) throws SchemaException
287    {
288    	Map<String,XmlObject> result = new HashMap<String,XmlObject>();
289    	getSchemas( wsdlUrl, result, loader, null );
290    	return result;
291    }
292    
293    /***
294     * Returns a map mapping urls to corresponding XmlSchema XmlObjects for the specified wsdlUrl
295     */
296    
297    public static void getSchemas( String wsdlUrl, Map<String,XmlObject> existing,  WsdlLoader loader, String tns ) throws SchemaException
298    {
299    	if( existing.containsKey( wsdlUrl ))
300    		return; 
301    	
302    	log.info( "Getting schema " + wsdlUrl );
303    	
304    	ArrayList errorList = new ArrayList();
305    	
306    	Map<String,XmlObject> result = new HashMap<String,XmlObject>();
307    	
308       try
309 		{
310 			XmlOptions options = new XmlOptions();
311 			options.setCompileNoValidation();
312 			options.setSaveUseOpenFrag();
313 			options.setErrorListener( errorList );
314 			options.setSaveSyntheticDocumentElement(new QName( Constants.XSD_NS, "schema"));
315 
316 			XmlObject xmlObject = loader.loadXmlObject(wsdlUrl, options);
317 
318 			Document dom = (Document) xmlObject.getDomNode();
319 			Node domNode = dom.getDocumentElement();
320 			if (domNode.getLocalName().equals("schema")
321 					&& domNode.getNamespaceURI().equals(
322 							Constants.XSD_NS))
323 			{
324 				// set targetNamespace (this happens if we are following an include statement)
325 				if( tns != null )
326 				{
327 					Element elm = ((Element)domNode);
328 					if( !elm.hasAttribute( "targetNamespace" ))
329 					{
330 						elm.setAttribute( "targetNamespace", tns );
331 					}
332 					
333 					// check for namespace prefix for targetNamespace
334 					NamedNodeMap attributes = elm.getAttributes();
335 					int c = 0;
336 					for( ; c < attributes.getLength(); c++ )
337 					{
338 						Node item = attributes.item( c );
339 						if( item.getNodeValue().equals( tns ) && item.getNodeName().startsWith( "xmlns" ))
340 							break;
341 					}
342 					
343 					if( c == attributes.getLength() )
344 						elm.setAttribute( "xmlns", tns );
345 				}
346 				
347 				result.put(wsdlUrl, xmlObject);
348 			}
349 			else
350 			{
351 				XmlObject[] schemas = xmlObject
352 						.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:schema");
353 
354 				for (int i = 0; i < schemas.length; i++)
355 				{
356 					XmlCursor xmlCursor = schemas[i].newCursor();
357 					String xmlText = xmlCursor.getObject().xmlText(options);
358 					schemas[i] = XmlObject.Factory.parse(xmlText, options);
359 					schemas[i].documentProperties().setSourceName(wsdlUrl);
360 					
361 					result.put(wsdlUrl + "@" + (i+1), schemas[i]);
362 				}
363 
364 				XmlObject[] wsdlImports = xmlObject
365 						.selectPath("declare namespace s='" + Constants.WSDL11_NS + "' .//s:import/@location");
366 				for (int i = 0; i < wsdlImports.length; i++)
367 				{
368 					String location = ((SimpleValue) wsdlImports[i]).getStringValue();
369 					if (location != null)
370 					{
371 						if (location.startsWith("file:")
372 								|| location.indexOf("://") > 0)
373 						{
374 							getSchemas(location, existing, loader, null);
375 						}
376 						else
377 						{
378 							getSchemas(Tools.joinRelativeUrl(wsdlUrl, location), existing, loader, null);
379 						}
380 					}
381 				}
382 			}
383 
384 			existing.putAll( result );
385 			
386 			XmlObject[] schemas = result.values().toArray(
387 					new XmlObject[result.size()]);
388 
389 			for (int c = 0; c < schemas.length; c++)
390 			{
391 				xmlObject = schemas[c];
392 
393 				XmlObject[] schemaImports = xmlObject
394 						.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:import/@schemaLocation");
395 				for (int i = 0; i < schemaImports.length; i++)
396 				{
397 					String location = ((SimpleValue) schemaImports[i])
398 							.getStringValue();
399 					if (location != null)
400 					{
401 						if (location.startsWith("file:")
402 								|| location.indexOf("://") > 0)
403 						{
404 							getSchemas(location, existing, loader, null);
405 						}
406 						else
407 						{
408 							getSchemas(Tools.joinRelativeUrl(wsdlUrl, location), existing, loader, null);
409 						}
410 					}
411 				}
412 
413 				XmlObject[] schemaIncludes = xmlObject
414 						.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:include/@schemaLocation");
415 				for (int i = 0; i < schemaIncludes.length; i++)
416 				{
417 					String location = ((SimpleValue) schemaIncludes[i])
418 							.getStringValue();
419 					if (location != null)
420 					{
421 						String targetNS = ((Document)xmlObject.getDomNode()).getDocumentElement().getAttribute( "targetNamespace" );
422 						
423 						if (location.startsWith("file:")
424 								|| location.indexOf("://") > 0)
425 						{
426 							getSchemas(location, existing, loader, targetNS);
427 						}
428 						else
429 						{
430 							getSchemas(Tools.joinRelativeUrl(wsdlUrl, location), existing, loader, targetNS);
431 						}
432 					}
433 				}
434 			}
435 		}
436 		catch (Exception e)
437 		{
438 			SoapUI.logError( e );
439 			throw new SchemaException( e, errorList );
440 		}
441    }
442    
443    /***
444     * Returns a map mapping urls to corresponding XmlObjects for the specified wsdlUrl
445     */
446    
447    public static Map<String,XmlObject> getDefinitionParts( WsdlLoader loader ) throws Exception
448    {
449    	HashMap<String, XmlObject> result = new HashMap<String,XmlObject>();
450 		getDefinitionParts( loader.getBaseURI(), result, loader );
451 		return result;
452    }
453    
454    public static void getDefinitionParts( String wsdlUrl, Map<String,XmlObject> existing, WsdlLoader loader ) throws Exception
455    {
456    	if( existing.containsKey( wsdlUrl ))
457    		return;
458    	
459       XmlObject xmlObject = loader.loadXmlObject( wsdlUrl, null );
460       existing.put( wsdlUrl, xmlObject );
461 
462     	XmlObject [] wsdlImports = xmlObject.selectPath("declare namespace s='" + Constants.WSDL11_NS + "' .//s:import");
463       for (int i = 0; i < wsdlImports.length; i++)
464       {
465          String location = wsdlImports[i].getDomNode().getAttributes().getNamedItem( "location" ).getNodeValue();
466          if( location != null )
467          {
468             if( location.startsWith( "file:" ) || location.indexOf( "://") > 0 )
469             {
470             	getDefinitionParts( location, existing, loader );
471             }
472             else
473             {
474             	getDefinitionParts( Tools.joinRelativeUrl( wsdlUrl, location ), existing, loader );
475             }
476          }
477       }
478       
479       XmlObject[] schemaImports = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:import/@schemaLocation");
480       for (int i = 0; i < schemaImports.length; i++)
481       {
482          String location = ((SimpleValue)schemaImports[i]).getStringValue();
483          if( location != null )
484          {
485             if( location.startsWith( "file:" ) || location.indexOf( "://") > 0 )
486             {
487             	getDefinitionParts( location, existing, loader );
488             }
489             else
490             {
491             	getDefinitionParts( Tools.joinRelativeUrl( wsdlUrl, location ), existing, loader );
492             }
493          }
494       }
495       
496       XmlObject[] schemaIncludes = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:include/@schemaLocation");
497       for (int i = 0; i < schemaIncludes.length; i++)
498       {
499          String location = ((SimpleValue)schemaIncludes[i]).getStringValue();
500          if( location != null  )
501          {
502             if( location.startsWith( "file:" ) || location.indexOf( "://") > 0 )
503             {
504             	getDefinitionParts( location, existing, loader );
505             }
506             else
507             {
508             	getDefinitionParts( Tools.joinRelativeUrl( wsdlUrl, location ), existing, loader );
509             }
510          }
511       }
512    }
513    
514    /***
515     * Extracts namespaces - used in tool integrations for mapping..
516     */
517 
518 	public static Collection<String> extractNamespaces( SchemaTypeSystem schemaTypes )
519 	{
520 		Set<String> namespaces = new HashSet<String>();
521 		SchemaType[] globalTypes = schemaTypes.globalTypes();
522 		for( int c = 0; c < globalTypes.length; c++ )
523 		{
524 			namespaces.add( globalTypes[c].getName().getNamespaceURI() );
525 		}
526 		
527 		namespaces.remove( Constants.SOAP11_ENVELOPE_NS );
528 		namespaces.remove( Constants.SOAP_ENCODING_NS );
529 		
530 		return namespaces;
531 	}
532    
533    /***
534     * Used when creating a TypeSystem from a complete collection of SchemaDocuments so that referenced 
535     * types are not downloaded (again)
536     */
537    
538 	public static void removeImports(XmlObject xmlObject) throws XmlException
539 	{
540 		 XmlObject[] imports = xmlObject
541        	.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:import");
542 		 
543 		 for( int c = 0; c < imports.length; c++ )
544 		 {
545 			 XmlCursor cursor = imports[c].newCursor();
546 			 cursor.removeXml();
547 			 cursor.dispose();
548 		 }
549 		 
550 		 XmlObject[] includes = xmlObject
551      		.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:include");
552 		 
553 		 for( int c = 0; c < includes.length; c++ )
554 		 {
555 			 XmlCursor cursor = includes[c].newCursor();
556 			 cursor.removeXml();
557 			 cursor.dispose();
558 		 }
559 	}
560 
561 	public static boolean isInstanceOf( SchemaType schemaType, SchemaType baseType )
562 	{
563 		if( schemaType == null )
564 			return false;
565 		return schemaType.equals(baseType) ? true : isInstanceOf( schemaType.getBaseType(), baseType );
566 	}
567 
568 	public static boolean isBinaryType(SchemaType schemaType)
569 	{
570 		return isInstanceOf( schemaType, XmlHexBinary.type ) ||
571 				isInstanceOf( schemaType, XmlBase64Binary.type );
572 	}
573 
574 	public static String getDocumentation( SchemaParticle particle, SchemaType schemaType )
575 	{
576 		String result = null;
577 		String xsPrefix = null;
578 		
579 		if( particle instanceof SchemaLocalElement )
580 		{
581 			SchemaAnnotation annotation = ((SchemaLocalElement)particle).getAnnotation();
582 			if( annotation != null )
583 			{
584 				XmlObject[] userInformation = annotation.getUserInformation();
585 				if( userInformation != null && userInformation.length > 0 )
586 				{
587 					XmlObject xmlObject = userInformation[0];
588 					XmlCursor cursor = xmlObject.newCursor();
589 					xsPrefix = cursor.prefixForNamespace( "http://www.w3.org/2001/XMLSchema" );
590 					cursor.dispose();
591 					
592 					result = xmlObject.xmlText(); // XmlUtils.getElementText( ( Element ) userInformation[0].getDomNode());
593 				}
594 			}
595 		}
596 		
597 		if( result == null && schemaType != null && schemaType.getAnnotation() != null )
598 		{
599 			XmlObject[] userInformation = schemaType.getAnnotation().getUserInformation();
600 			if( userInformation != null && userInformation.length > 0 )
601 			{
602 				XmlObject xmlObject = userInformation[0];
603 				XmlCursor cursor = xmlObject.newCursor();
604 				xsPrefix = cursor.prefixForNamespace( "http://www.w3.org/2001/XMLSchema" );
605 				cursor.dispose();
606 				result = xmlObject.xmlText(); // = XmlUtils.getElementText( ( Element ) userInformation[0].getDomNode());
607 			}
608 		}
609 		
610 		if( result != null )
611 		{
612 			result = result.trim();
613 			if( result.startsWith( "<" ) && result.endsWith( ">" ))
614 			{
615 				int ix = result.indexOf( '>' );
616 				if( ix > 0 )
617 				{
618 					result = result.substring( ix+1);
619 				}
620 				
621 				ix = result.lastIndexOf( '<' );
622 				if( ix >= 0 )
623 				{
624 					result = result.substring( 0, ix );
625 				}
626 			}
627 			
628 			if( xsPrefix == null || xsPrefix.length() == 0 )
629 				xsPrefix = "xs:";
630 			else 
631 				xsPrefix += ":";
632 			
633 			//result = result.trim().replaceAll( "<" + xsPrefix + "br/>", "\n" ).trim();
634 			result = result.trim().replaceAll( xsPrefix, "" ).trim();
635 			
636 			StringTokenizer st = new StringTokenizer( result, "\r\n" );
637 			StringBuffer buf = new StringBuffer( "<html><body>" );
638 			boolean added = false;
639 			
640 			while( st.hasMoreElements() )
641 			{
642 				String str = st.nextToken().trim();
643 				if( str.length() > 0 )
644 				{
645 					if( str.equals( "<br/>" ))
646 					{
647 						buf.append( "<br>" );
648 						added = false;
649 						continue;
650 					}
651 						
652 					if( added )
653 						buf.append( "<br>" );
654 					
655 					buf.append( str );
656 					added = true;
657 				}
658 			}
659 			buf.append( "</body></html>" );
660 			result = buf.toString();
661 		}
662 		
663 		return result;
664 	}
665 
666 	public static String [] getEnumerationValues( SchemaType schemaType, boolean addNull )
667 	{
668 		if( schemaType != null )
669 		{
670 			XmlAnySimpleType[] enumerationValues = schemaType.getEnumerationValues();
671 			if( enumerationValues != null && enumerationValues.length > 0 )
672 			{
673 				if( addNull )
674 				{
675 					String [] values = new String[enumerationValues.length+1];
676 					values[0] = null;
677 					
678 					for( int c = 1; c < values.length; c++ )
679 						values[c] = enumerationValues[c-1].getStringValue();
680 					
681 					return values;
682 				}
683 				else
684 				{
685 					String [] values = new String[enumerationValues.length];
686 					
687 					for( int c = 0; c < values.length; c++ )
688 						values[c] = enumerationValues[c].getStringValue();
689 					
690 					return values;
691 				}
692 			}
693 		}
694 		
695 		return new String[0];
696 	}
697 }