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