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