View Javadoc

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