View Javadoc

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