View Javadoc

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