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