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.wsdl.support.wsdl;
14  
15  import com.eviware.soapui.SoapUI;
16  import com.eviware.soapui.impl.support.definition.DefinitionLoader;
17  import com.eviware.soapui.impl.wsdl.support.CompressionSupport;
18  import com.eviware.soapui.impl.wsdl.support.PathUtils;
19  import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
20  import com.eviware.soapui.impl.wsdl.support.http.ProxyUtils;
21  import com.eviware.soapui.model.ModelItem;
22  import com.eviware.soapui.model.propertyexpansion.DefaultPropertyExpansionContext;
23  import com.eviware.soapui.model.settings.Settings;
24  import com.eviware.soapui.settings.HttpSettings;
25  import com.eviware.soapui.support.UISupport;
26  import com.eviware.soapui.support.swing.SwingWorker;
27  import com.eviware.soapui.support.types.StringToStringMap;
28  import com.eviware.x.form.XForm;
29  import com.eviware.x.form.XFormDialog;
30  import com.eviware.x.form.XFormDialogBuilder;
31  import com.eviware.x.form.XFormFactory;
32  import org.apache.commons.httpclient.*;
33  import org.apache.commons.httpclient.auth.*;
34  import org.apache.commons.httpclient.methods.GetMethod;
35  
36  import java.io.ByteArrayInputStream;
37  import java.io.File;
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.net.URL;
41  import java.util.HashMap;
42  import java.util.Map;
43  
44  /***
45   * WsdlLoader for URLs
46   *
47   * @author ole.matzura
48   */
49  
50  public class UrlWsdlLoader extends WsdlLoader implements DefinitionLoader
51  {
52     private HttpState state;
53     protected GetMethod getMethod;
54     private boolean aborted;
55     protected Map<String, byte[]> urlCache = new HashMap<String, byte[]>();
56     protected boolean finished;
57     private boolean useWorker;
58     private ModelItem contextModelItem;
59  
60     public UrlWsdlLoader( String url )
61     {
62        this( url, null );
63     }
64  
65     public UrlWsdlLoader( String url, ModelItem contextModelItem )
66     {
67        super( url );
68        this.contextModelItem = contextModelItem;
69        state = new HttpState();
70     }
71  
72     public boolean isUseWorker()
73     {
74        return useWorker;
75     }
76  
77     public void setUseWorker( boolean useWorker )
78     {
79        this.useWorker = useWorker;
80     }
81  
82     public InputStream load() throws Exception
83     {
84        return load( getBaseURI() );
85     }
86  
87     public synchronized InputStream load( String url ) throws Exception
88     {
89        if( !PathUtils.isHttpPath( url ) )
90        {
91           try
92           {
93              File file = new File( url.replace( '/', File.separatorChar ) );
94              if( file.exists() )
95                 url = file.toURI().toURL().toString();
96           }
97           catch( Exception e )
98           {
99           }
100       }
101 
102       if( urlCache.containsKey( url ) )
103       {
104          setNewBaseURI( url );
105          return new ByteArrayInputStream( urlCache.get( url ) );
106       }
107 
108       if( url.startsWith( "file:" ) )
109       {
110          return handleFile( url );
111       }
112 
113       log.debug( "Getting wsdl component from [" + url + "]" );
114 
115       createGetMethod( url );
116 
117       if( aborted )
118          return null;
119 
120       LoaderWorker worker = new LoaderWorker();
121       if( useWorker )
122          worker.start();
123       else
124          worker.construct();
125 
126       while( !aborted && !finished )
127       {
128          Thread.sleep( 200 );
129       }
130 
131       // wait for method to catch up - required in unit tests..
132       while( !aborted && getMethod.getResponseBody() == null )
133       {
134          Thread.sleep( 200 );
135       }
136 
137       try
138       {
139          if( aborted )
140          {
141             throw new Exception( "Load of url [" + url + "] was aborted" );
142          }
143          else
144          {
145             byte[] content = getMethod.getResponseBody();
146             if( content != null )
147             {
148                String compressionAlg = HttpClientSupport.getResponseCompressionType( getMethod );
149                if( compressionAlg != null )
150                   content = CompressionSupport.decompress( compressionAlg, content );
151 
152                urlCache.put( url, content );
153                String newUrl = getMethod.getURI().getURI();
154                if( !url.equals( newUrl ) )
155                   log.info( "BaseURI was redirected to [" + newUrl + "]" );
156                setNewBaseURI( newUrl );
157                urlCache.put( newUrl, content );
158                return new ByteArrayInputStream( content );
159             }
160             else
161             {
162                throw new Exception( "Failed to load url; " + getMethod.getStatusCode() + " - " + getMethod.getStatusText() );
163             }
164          }
165       }
166 
167       finally
168       {
169          getMethod.releaseConnection();
170       }
171    }
172 
173    protected InputStream handleFile( String url )
174            throws IOException
175    {
176       setNewBaseURI( url );
177       return new URL( url ).openStream();
178    }
179 
180    protected void createGetMethod( String url )
181    {
182       getMethod = new GetMethod( url );
183       getMethod.setDoAuthentication( true );
184       getMethod.getParams().setParameter( CredentialsProvider.PROVIDER, new WsdlCredentialsProvider() );
185 
186       if( SoapUI.getSettings().getBoolean( HttpSettings.AUTHENTICATE_PREEMPTIVELY ) )
187       {
188          HttpClientSupport.getHttpClient().getParams().setAuthenticationPreemptive( true );
189       }
190       else
191       {
192          HttpClientSupport.getHttpClient().getParams().setAuthenticationPreemptive( false );
193       }
194    }
195 
196    public final class LoaderWorker extends SwingWorker
197    {
198       public Object construct()
199       {
200          HttpClient httpClient = HttpClientSupport.getHttpClient();
201          try
202          {
203             Settings soapuiSettings = SoapUI.getSettings();
204 
205             HttpClientSupport.applyHttpSettings( getMethod, soapuiSettings );
206             HostConfiguration hostConfiguration = ProxyUtils.initProxySettings( soapuiSettings, state,
207                     new HostConfiguration(), getMethod.getURI().toString(),
208                     contextModelItem == null ? null : new DefaultPropertyExpansionContext( contextModelItem ) );
209 
210             httpClient.executeMethod( hostConfiguration, getMethod, state );
211          }
212          catch( Exception e )
213          {
214             return e;
215          }
216          finally
217          {
218             finished = true;
219          }
220 
221          return null;
222       }
223    }
224 
225    public boolean abort()
226    {
227       if( getMethod != null )
228          getMethod.abort();
229 
230       aborted = true;
231 
232       return true;
233    }
234 
235    public boolean isAborted()
236    {
237       return aborted;
238    }
239 
240    /***
241     * CredentialsProvider for providing login information during WSDL loading
242     *
243     * @author ole.matzura
244     */
245 
246    public final class WsdlCredentialsProvider implements CredentialsProvider
247    {
248       private XFormDialog basicDialog;
249       private XFormDialog ntDialog;
250 
251       public WsdlCredentialsProvider()
252       {
253       }
254 
255       public Credentials getCredentials( final AuthScheme authscheme, final String host, int port, boolean proxy )
256               throws CredentialsNotAvailableException
257       {
258          if( authscheme == null )
259          {
260             return null;
261          }
262          try
263          {
264             String pw = getPassword();
265             if( pw == null )
266                pw = "";
267 
268             if( authscheme instanceof NTLMScheme )
269             {
270                if( hasCredentials() )
271                {
272                   log.info( "Returning url credentials" );
273                   return new NTCredentials( getUsername(), pw, host, null );
274                }
275 
276                log.info( host + ":" + port + " requires Windows authentication" );
277                if( ntDialog == null )
278                {
279                   buildNtDialog();
280                }
281 
282                StringToStringMap values = new StringToStringMap();
283                values.put( "Info", "Authentication required for [" + host + ":" + port + "]" );
284                ntDialog.setValues( values );
285 
286                if( ntDialog.show() )
287                {
288                   values = ntDialog.getValues();
289                   return new NTCredentials( values.get( "Username" ), values.get( "Password" ), host, values.get( "Domain" ) );
290                }
291                else
292                   throw new CredentialsNotAvailableException( "Operation cancelled" );
293             }
294             else if( authscheme instanceof RFC2617Scheme )
295             {
296                if( hasCredentials() )
297                {
298                   log.info( "Returning url credentials" );
299                   return new UsernamePasswordCredentials( getUsername(), pw );
300                }
301 
302                log.info( host + ":" + port + " requires authentication with the realm '" + authscheme.getRealm() + "'" );
303                if( basicDialog == null )
304                   buildBasicDialog();
305 
306                StringToStringMap values = new StringToStringMap();
307                values.put( "Info", "Authentication required for [" + host + ":" + port + "]" );
308                basicDialog.setValues( values );
309                if( basicDialog.show() )
310                {
311                   values = basicDialog.getValues();
312                   return new UsernamePasswordCredentials( values.get( "Username" ), values.get( "Password" ) );
313                }
314                else
315                   throw new CredentialsNotAvailableException( "Operation cancelled" );
316 
317             }
318             else
319             {
320                throw new CredentialsNotAvailableException( "Unsupported authentication scheme: "
321                        + authscheme.getSchemeName() );
322             }
323          }
324          catch( IOException e )
325          {
326             throw new CredentialsNotAvailableException( e.getMessage(), e );
327          }
328       }
329 
330       private void buildBasicDialog()
331       {
332          XFormDialogBuilder builder = XFormFactory.createDialogBuilder( "Basic Authentication" );
333          XForm mainForm = builder.createForm( "Basic" );
334          mainForm.addLabel( "Info", "" );
335          mainForm.addTextField( "Username", "Username for authentication", XForm.FieldType.TEXT );
336          mainForm.addTextField( "Password", "Password for authentication", XForm.FieldType.PASSWORD );
337 
338          basicDialog = builder.buildDialog( builder.buildOkCancelActions(),
339                  "Specify Basic Authentication Credentials", UISupport.OPTIONS_ICON );
340       }
341 
342       private void buildNtDialog()
343       {
344          XFormDialogBuilder builder = XFormFactory.createDialogBuilder( "NT Authentication" );
345          XForm mainForm = builder.createForm( "Basic" );
346          mainForm.addLabel( "Info", "" );
347          mainForm.addTextField( "Username", "Username for authentication", XForm.FieldType.TEXT );
348          mainForm.addTextField( "Password", "Password for authentication", XForm.FieldType.PASSWORD );
349          mainForm.addTextField( "Domain", "NT Domain for authentication", XForm.FieldType.TEXT );
350 
351          ntDialog = builder.buildDialog( builder.buildOkCancelActions(),
352                  "Specify NT Authentication Credentials", UISupport.OPTIONS_ICON );
353       }
354    }
355 
356    public void close()
357 	{
358 	}
359 }