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.support.definition.support;
14  
15  import java.util.ArrayList;
16  import java.util.HashMap;
17  import java.util.List;
18  import java.util.Map;
19  
20  import org.apache.log4j.Logger;
21  import org.apache.xmlbeans.SchemaTypeLoader;
22  import org.apache.xmlbeans.SchemaTypeSystem;
23  
24  import com.eviware.soapui.SoapUI;
25  import com.eviware.soapui.impl.support.AbstractInterface;
26  import com.eviware.soapui.impl.support.DefinitionContext;
27  import com.eviware.soapui.impl.support.definition.DefinitionCache;
28  import com.eviware.soapui.impl.support.definition.DefinitionLoader;
29  import com.eviware.soapui.impl.support.definition.InterfaceDefinition;
30  import com.eviware.soapui.impl.support.definition.InterfaceDefinitionPart;
31  import com.eviware.soapui.impl.wsdl.support.PathUtils;
32  import com.eviware.soapui.impl.wsdl.support.xsd.SchemaException;
33  import com.eviware.soapui.support.UISupport;
34  import com.eviware.x.dialogs.Worker;
35  import com.eviware.x.dialogs.XProgressDialog;
36  import com.eviware.x.dialogs.XProgressMonitor;
37  
38  /***
39   * Holder for InterfaceDefinitions and related SchemaTypeLoader types
40   * 
41   * @author Ole.Matzura
42   */
43  
44  public abstract class AbstractDefinitionContext<T extends AbstractInterface, T2 extends DefinitionLoader, T3 extends AbstractInterfaceDefinition<T>>
45  		implements DefinitionContext
46  {
47  	private String url;
48  	private T3 definition;
49  	private boolean loaded;
50  	private SchemaException schemaException;
51  
52  	private final static Logger log = Logger.getLogger( AbstractDefinitionContext.class );
53  
54  	private T2 currentLoader;
55  	private T iface;
56  
57  	private static Map<String, InterfaceDefinition> definitionCache = new HashMap<String, InterfaceDefinition>();
58  	private static Map<String, Integer> urlReferences = new HashMap<String, Integer>();
59  
60  	public AbstractDefinitionContext( String url, T iface )
61  	{
62  		this.url = PathUtils.ensureFilePathIsUrl( url );
63  		this.iface = iface;
64  	}
65  
66  	public AbstractDefinitionContext( String url )
67  	{
68  		this( url, null );
69  	}
70  
71  	public T getInterface()
72  	{
73  		return iface;
74  	}
75  
76  	public T3 getInterfaceDefinition() throws Exception
77  	{
78  		loadIfNecessary();
79  		return ( T3 )( definition == null ? definitionCache.get( url ) : definition );
80  	}
81  
82  	public synchronized boolean isLoaded()
83  	{
84  		return loaded;
85  	}
86  
87  	public synchronized boolean loadIfNecessary() throws Exception
88  	{
89  		if( !loaded )
90  			load();
91  		return loaded;
92  	}
93  
94  	public synchronized void setDefinition( String url, boolean updateCache ) throws Exception
95  	{
96  		if( !url.equals( this.url ) )
97  		{
98  			this.url = url;
99  
100 			if( updateCache )
101 			{
102 				definitionCache.remove( url );
103 				loaded = false;
104 				load();
105 			}
106 
107 			// FIXME Refactoring: loaded = (definition != null) ?
108 			loaded = iface != null && definitionCache.containsKey( url );
109 		}
110 	}
111 
112 	public synchronized boolean load() throws Exception
113 	{
114 		return load( null );
115 	}
116 
117 	public synchronized boolean load( T2 wsdlLoader ) throws Exception
118 	{
119 		// only use cache if iface has been specified
120 		if( !loaded && iface != null )
121 		{
122 			// FIXME Refactoring: loaded = (definition != null) ?
123 			loaded = definitionCache.containsKey( url );
124 		}
125 
126 		if( loaded )
127 			return true;
128 
129 		// always use progressDialog since files can import http urls
130 		XProgressDialog progressDialog = UISupport.getDialogs().createProgressDialog( "Loading Definition", 3,
131 				"Loading definition..", true );
132 
133 		Loader loader = new Loader( wsdlLoader );
134 		progressDialog.run( loader );
135 
136 		// Get the value. It is the responsibility of the progressDialog to
137 		// wait for the other thread to finish.
138 		if( loader.hasError() )
139 		{
140 			if( loader.getError() instanceof SchemaException )
141 			{
142 				schemaException = ( SchemaException )loader.getError();
143 				ArrayList<?> errorList = schemaException.getErrorList();
144 
145 				log.error( "Error loading schema types from " + url + ", see log for details" );
146 
147 				if( errorList != null )
148 				{
149 					for( int c = 0; c < errorList.size(); c++ )
150 					{
151 						log.error( errorList.get( c ).toString() );
152 					}
153 				}
154 			}
155 			else
156 				throw new Exception( loader.getError() );
157 		}
158 		else
159 		{
160 			loaded = true;
161 		}
162 
163 		return loaded;
164 	}
165 
166 	public SchemaTypeLoader getSchemaTypeLoader() throws Exception
167 	{
168 		loadIfNecessary();
169 		return iface != null ? definitionCache.get( url ).getSchemaTypeLoader() : definition != null ? definition
170 				.getSchemaTypeLoader() : null;
171 	}
172 
173 	public SchemaException getSchemaException()
174 	{
175 		return schemaException;
176 	}
177 
178 	private class Loader extends Worker.WorkerAdapter
179 	{
180 		private Throwable error;
181 		private T2 wsdlLoader;
182 
183 		public Loader( T2 wsdlLoader )
184 		{
185 			super();
186 			this.wsdlLoader = wsdlLoader;
187 		}
188 
189 		private T2 getDefinitionLoader()
190 		{
191 			if( wsdlLoader != null )
192 			{
193 				return wsdlLoader;
194 			}
195 			else
196 			{
197 				return createDefinitionLoader( url );
198 			}
199 		}
200 
201 		public boolean hasError()
202 		{
203 			return error != null;
204 		}
205 
206 		public Object construct( XProgressMonitor monitor )
207 		{
208 			try
209 			{
210 				DefinitionCache cache = iface == null ? new StandaloneDefinitionCache<T>()
211 						: new InterfaceConfigDefinitionCache<T>( iface );
212 
213 				if( !cache.validate() )
214 				{
215 					monitor.setProgress( 1, "Caching Definition from url [" + url + "]" );
216 
217 					currentLoader = getDefinitionLoader();
218 					currentLoader.setProgressMonitor( monitor, 2 );
219 
220 					cache.update( currentLoader );
221 
222 					if( currentLoader.isAborted() )
223 						throw new Exception( "Loading of Definition from [" + url + "] was aborted" );
224 				}
225 
226 				monitor.setProgress( 1, "Loading Definition from " + ( iface == null ? "url" : "cache" ) );
227 
228 				log.debug( "Loading Definition..." );
229 				cacheDefinition( cache );
230 				return null;
231 			}
232 			catch( Throwable e )
233 			{
234 				log.error( "Loading of definition failed for [" + url + "]; " + e );
235 				SoapUI.logError( e );
236 				this.error = e;
237 				return e;
238 			}
239 			finally
240 			{
241 				currentLoader = null;
242 			}
243 		}
244 
245 		public Throwable getError()
246 		{
247 			return error;
248 		}
249 
250 		public boolean onCancel()
251 		{
252 			if( currentLoader == null )
253 				return false;
254 
255 			return currentLoader.abort();
256 		}
257 	}
258 
259 	private void cacheDefinition( DefinitionCache cache ) throws Exception
260 	{
261 		currentLoader = createDefinitionLoader( cache );
262 		currentLoader.setProgressInfo( "Loading Definition" );
263 		definition = loadDefinition( currentLoader );
264 		definition.setDefinitionCache( cache );
265 
266 		log.debug( "Loaded Definition: " + ( definition != null ? "ok" : "null" ) );
267 
268 		if( !currentLoader.isAborted() && iface != null && iface.isDefinitionShareble() )
269 		{
270 			definitionCache.put( url, definition );
271 			if( urlReferences.containsKey( url ) )
272 			{
273 				urlReferences.put( url, urlReferences.get( url ) + 1 );
274 			}
275 			else
276 			{
277 				urlReferences.put( url, 1 );
278 			}
279 		}
280 
281 		if( currentLoader.isAborted() )
282 			throw new Exception( "Loading of Definition from [" + url + "] was aborted" );
283 
284 		loaded = true;
285 	}
286 
287 	protected abstract T2 createDefinitionLoader( DefinitionCache definitionCache );
288 
289 	protected abstract T2 createDefinitionLoader( String url );
290 
291 	protected abstract T3 loadDefinition( T2 loader ) throws Exception;
292 
293 	public void release()
294 	{
295 		if( iface != null && urlReferences.containsKey( url ) )
296 		{
297 			Integer i = urlReferences.get( url );
298 			if( i.intValue() <= 1 )
299 			{
300 				urlReferences.remove( url );
301 				definitionCache.remove( url );
302 			}
303 			else
304 			{
305 				urlReferences.put( url, i - 1 );
306 			}
307 		}
308 	}
309 
310 	public SchemaTypeSystem getSchemaTypeSystem() throws Exception
311 	{
312 		if( !isLoaded() )
313 			load();
314 
315 		if( !definitionCache.containsKey( url ) )
316 			return null;
317 
318 		return definitionCache.get( url ).getSchemaTypeSystem();
319 	}
320 
321 	public boolean hasSchemaTypes()
322 	{
323 		try
324 		{
325 			loadIfNecessary();
326 		}
327 		catch( Exception e )
328 		{
329 			SoapUI.logError( e );
330 			return false;
331 		}
332 
333 		InterfaceDefinition def = ( definition != null ? definition : definitionCache.get( url ) );
334 		return def != null && def.hasSchemaTypes();
335 	}
336 
337 	public String getUrl()
338 	{
339 		return url;
340 	}
341 
342 	public void setInterface( T iface )
343 	{
344 		if( this.iface == null && iface != null )
345 		{
346 			if( definition != null )
347 			{
348 				if( definition.getDefinitionCache().validate() )
349 				{
350 					InterfaceConfigDefinitionCache cache = new InterfaceConfigDefinitionCache( iface );
351 					try
352 					{
353 						cache.importCache( definition.getDefinitionCache() );
354 					}
355 					catch( Exception e )
356 					{
357 						SoapUI.logError( e );
358 					}
359 
360 					definition.setDefinitionCache( cache );
361 				}
362 
363 				definition.setIface( iface );
364 				definitionCache.put( url, definition );
365 			}
366 			else
367 			{
368 				loaded = false;
369 			}
370 		}
371 
372 		this.iface = iface;
373 	}
374 
375 	public static void uncache( String url )
376 	{
377 		definitionCache.remove( url );
378 		urlReferences.remove( url );
379 	}
380 
381 	public void reload() throws Exception
382 	{
383 		getDefinitionCache().clear();
384 		definitionCache.remove( url );
385 		loaded = false;
386 		load();
387 	}
388 
389 	public boolean isCached()
390 	{
391 		return isLoaded() && definition != null && definition.getDefinitionCache() != null;
392 	}
393 
394 	public List<InterfaceDefinitionPart> getDefinitionParts() throws Exception
395 	{
396 		loadIfNecessary();
397 
398 		return getInterfaceDefinition().getDefinitionParts();
399 	}
400 
401 	public DefinitionCache getDefinitionCache() throws Exception
402 	{
403 		loadIfNecessary();
404 
405 		return getInterfaceDefinition().getDefinitionCache();
406 	}
407 }