View Javadoc

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