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.wsdl;
14  
15  import java.util.ArrayList;
16  import java.util.Collection;
17  import java.util.HashMap;
18  import java.util.HashSet;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Set;
22  
23  import javax.wsdl.Definition;
24  import javax.wsdl.factory.WSDLFactory;
25  import javax.wsdl.xml.WSDLReader;
26  import javax.xml.namespace.QName;
27  
28  import org.apache.log4j.Logger;
29  import org.apache.xmlbeans.SchemaType;
30  import org.apache.xmlbeans.SchemaTypeLoader;
31  import org.apache.xmlbeans.SchemaTypeSystem;
32  import org.apache.xmlbeans.XmlObject;
33  import org.apache.xmlbeans.XmlOptions;
34  
35  import com.eviware.soapui.config.DefinitionCacheConfig;
36  import com.eviware.soapui.config.DefintionPartConfig;
37  import com.eviware.soapui.impl.wsdl.WsdlInterface;
38  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
39  import com.eviware.soapui.impl.wsdl.support.xsd.SchemaException;
40  import com.eviware.soapui.impl.wsdl.support.xsd.SchemaUtils;
41  import com.eviware.soapui.support.NullProgressDialog;
42  import com.eviware.soapui.support.UISupport;
43  import com.eviware.x.dialogs.Worker;
44  import com.eviware.x.dialogs.XProgressDialog;
45  import com.eviware.x.dialogs.XProgressMonitor;
46  
47  /***
48   * Holder for WSDL4J Definitions and related SchemaTypeLoader types
49   * 
50   * @author Ole.Matzura
51   */
52  
53  public class WsdlContext 
54  {
55     private String url;
56     private Definition definition;
57     private SchemaTypeLoader schemaTypes;
58     private boolean loaded;
59  	private SchemaException schemaException;
60  	
61  	private final static Logger log = Logger.getLogger( WsdlContext.class );
62  	private SoapVersion soapVersion;
63  	private DefinitionCacheConfig cache;
64  	private WsdlLoader currentLoader;
65  	private final WsdlInterface iface;
66  	private WSDLFactory factory;
67  	private WSDLReader wsdlReader;
68  
69     public WsdlContext( String url, SoapVersion soapVersion, DefinitionCacheConfig cache, WsdlInterface iface )
70     {
71     	this.url = url;
72  		this.soapVersion = soapVersion;
73  		this.cache = cache;
74  		this.iface = iface;
75     }
76  	
77     public DefinitionCacheConfig getCacheConfig()
78     {
79     	return cache;
80     }
81     
82     public Definition getDefinition() throws Exception
83     {
84        loadIfNecessary();
85        return definition;
86     }
87     
88     public boolean isLoaded()
89     {
90     	return loaded;
91     }
92     
93     public synchronized boolean loadIfNecessary() throws Exception
94     {
95     	if( !loaded )
96           load();
97     	
98     	return loaded;
99     }
100    
101    public synchronized void setDefinition( String url, DefinitionCacheConfig cache ) 
102    {
103    	this.url = url;
104 		this.cache = null;
105    	loaded = false;
106    }
107      
108    public synchronized void load() throws Exception
109    {
110    	if( loaded )
111    		return;
112    	
113       /// TODO Eclipse jbossws: Discuss progress dialogs for "file:" URLs
114       XProgressDialog progressDialog;
115       if( url.startsWith("file:") )
116       {
117          progressDialog = new NullProgressDialog();
118       }
119       else
120       {
121          progressDialog = UISupport.getDialogs().createProgressDialog(
122                "Loading WSDL", 3, "Loading definition..", true );
123       }
124       
125    	Loader loader = new Loader();
126       progressDialog.run( loader);
127       
128       // Get the value. It is the responsibility of the progressDialog to
129       // wait for the other thread to finish.
130       if( loader.hasError() )
131       {
132          if( loader.getError() instanceof SchemaException )
133          {
134          	schemaException = (SchemaException) loader.getError();
135          	ArrayList errorList = schemaException.getErrorList();
136          	
137          	if( errorList != null )
138          	{
139 	         	log.error( "Error loading schema types from " + url + ", see log for details" );
140 	         	for( int c = 0; c < errorList.size(); c++ )
141 	         	{
142 	         		log.error( errorList.get( c ).toString() );
143 	         	}
144          	}
145          	
146         		UISupport.showErrorMessage( "Error loading schema types from " + url + ", see log for details" );
147          }
148          else throw loader.getError();
149       }
150       else loaded = true;
151    }
152 
153    public SchemaTypeLoader getSchemaTypeLoader() throws Exception
154    {
155       loadIfNecessary();
156       return schemaTypes;
157    }
158    
159    public SchemaException getSchemaException()
160    {
161    	return schemaException;
162    }
163 
164    private class Loader extends Worker.WorkerAdapter
165    {
166       private Exception error;
167       
168       public boolean hasError()
169 		{
170 			return error != null;
171 		}
172 
173 		public Object construct(XProgressMonitor monitor)
174       {
175       	try
176       	{
177 				if( !validateCache( cache ) )
178 				{
179 				   monitor.setProgress( 1, "Caching definition from url [" + url + "]" ); 
180 				   
181 				   currentLoader = new UrlWsdlLoader( url );
182 				   cache = iface == null ? WsdlLoader.cacheWsdl( (UrlWsdlLoader) currentLoader ) : 
183 				   	iface.cacheDefinition( (UrlWsdlLoader) currentLoader );
184 				   
185 				   if( currentLoader.isAborted() )
186 				   	throw new Exception( "Loading of WSDL from [" + url + "] was aborted" );
187 				}
188       		 
189             monitor.setProgress( 1, "Loading definition from " + (cache == null ? "url" : "cache") );
190             
191             log.debug( "Loading definition from " + (cache == null ? "url" : "cache") );
192             loadDefinitions( cache == null ? new UrlWsdlLoader( url ) : new CachedWsdlLoader( cache ));
193             return null;
194          }
195          catch (Exception e)
196          {
197          	log.error( "Loading of definition failed for [" + url + "]; " + e );
198          	e.printStackTrace();
199             this.error = e;
200             return e;
201          }
202          finally
203          {
204             currentLoader = null;
205          }
206       }
207       
208       public Exception getError()
209       {
210          return error;
211       }
212       
213    	public boolean onCancel()
214    	{
215    		if( currentLoader == null )
216    			return false;
217 
218    		return currentLoader.abort();
219    	}
220    }
221 
222    private void loadDefinitions( WsdlLoader loader ) throws Exception
223    {
224    	currentLoader = loader;
225    	
226    	if( factory == null )
227    	{
228 	      factory = WSDLFactory.newInstance();
229 			wsdlReader = factory.newWSDLReader();
230 			wsdlReader.setFeature("javax.wsdl.verbose", true);
231 	      wsdlReader.setFeature("javax.wsdl.importDocuments", true);
232    	}
233 
234       definition = wsdlReader.readWSDL( loader );
235       log.debug( "Loaded definition: " + (definition != null ? "ok" : "null") );
236 
237       if( !currentLoader.isAborted() )
238       	schemaTypes = SchemaUtils.loadSchemaTypes(url, soapVersion, loader);
239       else 
240       	throw new Exception( "Loading of WSDL from [" + url + "] was aborted" );
241    }
242    
243 	public boolean validateCache(DefinitionCacheConfig cache)
244 	{
245 		if( cache == null )
246 			return false;
247 		
248 		if( cache.getRootPart() == null )
249 			return false;
250 		
251 		if( cache.sizeOfPartArray() == 0 )
252 			return false;
253 		
254 		return true;
255 	}
256 
257 	public SchemaTypeSystem getSchemaTypeSystem() throws Exception
258 	{
259       if( !loaded )
260          load();
261 		
262 		if( schemaTypes == null )
263 			return null;
264 		
265 		return schemaTypes.findElement( new QName("http://schemas.xmlsoap.org/soap/envelope/", "Envelope")).getTypeSystem();
266 	}
267    
268    public boolean hasSchemaTypes() throws Exception
269    {
270       loadIfNecessary();
271       return schemaTypes != null;
272    }
273 
274    public SchemaType findType(QName typeName) throws Exception
275    {
276       loadIfNecessary();
277       return schemaTypes == null ? null : schemaTypes.findType( typeName );
278    }
279 
280    public String getUrl()
281    {
282       return url;
283    }
284 
285 	public Collection<String> getDefinedNamespaces() throws Exception
286 	{
287       loadIfNecessary();
288       Set<String> namespaces = new HashSet<String>();
289       
290       if( schemaTypes != null )
291       {
292       	namespaces.addAll( SchemaUtils.extractNamespaces( getSchemaTypeSystem() ));
293       	
294       	namespaces.remove( "http://www.w3.org/2005/05/xmlmime" );
295       	namespaces.remove( "http://ws-i.org/profiles/basic/1.1/xsd" );
296       	namespaces.remove( "http://www.w3.org/2004/08/xop/include" );
297       }
298       
299       if( definition != null )
300       	namespaces.add( definition.getTargetNamespace() );
301       
302       return namespaces;
303 	}
304 
305 	public SoapVersion getSoapVersion()
306 	{
307 		return soapVersion;
308 	}
309 
310 	public void setSoapVersion(SoapVersion soapVersion)
311 	{
312 		this.soapVersion = soapVersion;
313 	}
314 
315 	public Map<String, XmlObject> getDefinitionParts() throws Exception
316 	{
317 		Map<String,XmlObject> result = new HashMap<String,XmlObject>();
318 		
319 		if( cache == null )
320 			return SchemaUtils.getDefinitionParts( new UrlWsdlLoader( url ));
321 		
322 		List<DefintionPartConfig> partList = cache.getPartList();
323 		for( DefintionPartConfig part : partList )
324 		{
325 			String str = part.getContent().toString();
326 			result.put( part.getUrl(), XmlObject.Factory.parse( str, new XmlOptions().setLoadLineNumbers() ) );
327 		}
328 		
329 		return result;
330 	}
331 
332 	public void setDefinitionCache(DefinitionCacheConfig definitionCache)
333 	{
334 		this.cache = definitionCache;
335 	}
336 }