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