View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 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.awt.event.ActionEvent;
16  import java.io.ByteArrayInputStream;
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 javax.swing.AbstractAction;
24  
25  import org.apache.commons.httpclient.Credentials;
26  import org.apache.commons.httpclient.HostConfiguration;
27  import org.apache.commons.httpclient.HttpClient;
28  import org.apache.commons.httpclient.HttpState;
29  import org.apache.commons.httpclient.NTCredentials;
30  import org.apache.commons.httpclient.UsernamePasswordCredentials;
31  import org.apache.commons.httpclient.auth.AuthScheme;
32  import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
33  import org.apache.commons.httpclient.auth.CredentialsProvider;
34  import org.apache.commons.httpclient.auth.NTLMScheme;
35  import org.apache.commons.httpclient.auth.RFC2617Scheme;
36  import org.apache.commons.httpclient.methods.GetMethod;
37  
38  import com.eviware.soapui.SoapUI;
39  import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
40  import com.eviware.soapui.impl.wsdl.support.http.ProxyUtils;
41  import com.eviware.soapui.model.settings.Settings;
42  import com.eviware.soapui.support.UISupport;
43  import com.eviware.soapui.support.action.ActionList;
44  import com.eviware.soapui.support.action.DefaultActionList;
45  import com.eviware.soapui.support.swing.SwingWorker;
46  import com.eviware.soapui.support.types.StringToStringMap;
47  import com.eviware.x.form.XForm;
48  import com.eviware.x.form.XFormDialog;
49  import com.eviware.x.form.XFormDialogBuilder;
50  import com.eviware.x.form.XFormFactory;
51  
52  public class UrlWsdlLoader extends WsdlLoader 
53  {
54  	private HttpState state;
55  	private GetMethod getMethod;
56  	private boolean aborted;
57  	private Map<String,byte[]> wsdlCache = new HashMap<String,byte[]>();
58  	private boolean finished;
59  	
60  	public UrlWsdlLoader(String url)
61  	{
62  		super( url );
63  		state = new HttpState();
64  	}
65  
66  	public synchronized InputStream load( String url ) throws Exception
67  	{
68  		if( wsdlCache.containsKey( url ))
69  		{
70  			return new ByteArrayInputStream( wsdlCache.get( url ) );
71  		}
72  		
73  		if( url.startsWith( "file:" ))
74  			return new URL( url ).openStream();
75  		
76  		log.debug( "Getting wsdl component from [" + url + "]" );
77  		
78  		createGetMethod(url);
79  		
80  		if( aborted )
81  			return null;
82  		
83  		LoaderWorker worker = new LoaderWorker();
84  		worker.start();
85  		
86  		while( !aborted && !finished )
87  		{
88  			Thread.sleep( 200 );
89  		}
90  		
91  		// wait for method to catch up - required in unit tests..
92  		while( !aborted && getMethod.getResponseBody() == null )
93  		{
94  			Thread.sleep( 200 );
95  		}
96  		
97  		try
98  		{
99  			if (aborted)
100 			{
101 				throw new Exception("Load of url [" + url + "] was aborted");
102 			}
103 			else
104 			{
105 				byte[] content = getMethod.getResponseBody();
106 				if( content != null )
107 				{
108 					if (HttpClientSupport.isZippedResponse( getMethod ))
109 					{
110 						content = HttpClientSupport.decompress( content );
111 					}
112 					
113 					wsdlCache.put(url, content);
114 					return new ByteArrayInputStream(content);
115 				}
116 				else
117 				{
118 					throw new Exception("Failed to load url; " + getMethod.getStatusCode() + " - " + getMethod.getStatusText());
119 				}
120 			}
121 		}
122 	
123 		finally
124 		{
125 			getMethod.releaseConnection();
126 		}		
127 	}
128 
129 	private void createGetMethod(String url)
130 	{
131 		getMethod = new GetMethod( url );
132 		getMethod.getParams().setParameter(CredentialsProvider.PROVIDER, new WsdlCredentialsProvider());
133 		getMethod.setDoAuthentication(true);
134 	}
135 	
136 	private final class LoaderWorker extends SwingWorker
137 	{
138 		public Object construct()
139 		{
140 			HttpClient httpClient = HttpClientSupport.getHttpClient();
141 			try
142 			{
143 				Settings soapuiSettings = SoapUI.getSettings();
144 				
145 				HttpClientSupport.applyHttpSettings( getMethod, soapuiSettings );
146 				HostConfiguration hostConfiguration = ProxyUtils.initProxySettings( soapuiSettings, state, new HostConfiguration(), getMethod.getURI().toString() );
147 				httpClient.executeMethod( hostConfiguration,	getMethod, state );
148 			}
149 			catch (Exception e)
150 			{
151 				return e;
152 			}
153 			finally
154 			{
155 				finished = true;
156 			}
157 			
158 			return null;
159 		}
160 	}
161 	
162 	public boolean abort()
163 	{
164 		if( getMethod != null )
165 			getMethod.abort();
166 		
167 		aborted = true;
168 		
169 		return true;
170 	}
171 
172 	public boolean isAborted()
173 	{
174 		return aborted;
175 	}
176 
177 	public static final class WsdlCredentialsProvider implements CredentialsProvider
178 	{	
179 		private XFormDialog basicDialog;
180 		private XFormDialog ntDialog;
181 		private XFormDialog dialog;
182 		public boolean canceled;
183 
184 		public WsdlCredentialsProvider()
185 		{
186 		}
187 
188 		public Credentials getCredentials(final AuthScheme authscheme, final String host, int port, boolean proxy)
189 		throws CredentialsNotAvailableException
190 		{
191 			if (authscheme == null)
192 			{
193 				return null;
194 			}
195 			try
196 			{
197 				if (authscheme instanceof NTLMScheme)
198 				{
199 					log.info(host + ":" + port + " requires Windows authentication");
200 					if( ntDialog == null )
201 					{
202 						buildNtDialog();
203 					}
204 					
205 					dialog = ntDialog;
206 
207 					StringToStringMap values = new StringToStringMap();
208 					values.put( "Info", "Authentication required for [" + host + ":" + port + "]" );
209 					ntDialog.setValues( values );
210 					ntDialog.setVisible( true );
211 					
212 					if( canceled )
213 						throw new CredentialsNotAvailableException("Operation cancelled");
214 					
215 					values = ntDialog.getValues();
216 					
217 					return new NTCredentials(values.get( "Username"), values.get( "Password"), host, values.get( "Domain"));
218 				}
219 				else if (authscheme instanceof RFC2617Scheme)
220 				{
221 					log.info(host + ":" + port + " requires authentication with the realm '" + authscheme.getRealm() + "'");
222 					if( basicDialog == null )
223 						buildBasicDialog();
224 					
225 					dialog = basicDialog;
226 					
227 					StringToStringMap values = new StringToStringMap();
228 					values.put( "Info", "Authentication required for [" + host + ":" + port + "]" );
229 					basicDialog.setValues( values );
230 					basicDialog.setVisible( true );
231 					
232 					if( canceled )
233 						throw new CredentialsNotAvailableException("Operation cancelled");
234 
235 					values = basicDialog.getValues();
236 					
237 					return new UsernamePasswordCredentials(values.get( "Username"), values.get( "Password"));
238 				}
239 				else
240 				{
241 					throw new CredentialsNotAvailableException("Unsupported authentication scheme: "
242 							+ authscheme.getSchemeName());
243 				}
244 			}
245 			catch (IOException e)
246 			{
247 				throw new CredentialsNotAvailableException(e.getMessage(), e);
248 			}
249 		}
250 
251 		private void buildBasicDialog()
252 		{
253 			XFormDialogBuilder builder = XFormFactory.createDialogBuilder( "Basic Authentication" );
254 			XForm mainForm = builder.createForm( "Basic" );
255 			mainForm.addLabel( "Info", "" );
256 			mainForm.addTextField( "Username", "Username for authentication", XForm.FieldType.TEXT ); 
257 			mainForm.addTextField( "Password", "Password for authentication", XForm.FieldType.PASSWORD ); 
258 			
259 			basicDialog = builder.buildDialog( buildDefaultActions(), 
260 					"Specify Basic Authentication Credentials", UISupport.OPTIONS_ICON );
261 		}
262 
263 		private void buildNtDialog()
264 		{
265 			XFormDialogBuilder builder = XFormFactory.createDialogBuilder( "NT Authentication" );
266 			XForm mainForm = builder.createForm( "Basic" );
267 			mainForm.addLabel( "Info", "" );
268 			mainForm.addTextField( "Username", "Username for authentication", XForm.FieldType.TEXT ); 
269 			mainForm.addTextField( "Password", "Password for authentication", XForm.FieldType.PASSWORD ); 
270 			mainForm.addTextField( "Domain", "NT Domain for authentication", XForm.FieldType.TEXT ); 
271 			
272 			ntDialog = builder.buildDialog( buildDefaultActions(), 
273 					"Specify NT Authentication Credentials", UISupport.OPTIONS_ICON );
274 		}
275 		
276 		public ActionList buildDefaultActions()
277 		{
278 			ActionList actions = new DefaultActionList( "Actions" );
279 			actions.addAction( new OkAction() );
280 			actions.addAction( new CancelAction() );
281 			return actions;
282 		}
283 		
284 		protected final class CancelAction extends AbstractAction
285 		{
286 			public CancelAction()
287 			{
288 				super( "Cancel" );
289 			}
290 			
291 			public void actionPerformed(ActionEvent e)
292 			{
293 				canceled = true;
294 				closeDialog();
295 			}
296 		}
297 		
298 		public void closeDialog()
299 		{
300 			if( dialog != null )
301 				dialog.setVisible( false );
302 		}
303 		
304 		protected final class OkAction extends AbstractAction
305 		{
306 			public OkAction()
307 			{
308 				super( "OK" );
309 			}
310 
311 			public void actionPerformed(ActionEvent e)
312 			{
313 				canceled = false;
314 				closeDialog();
315 			}
316 		}
317 	}
318 
319 	public void close()
320 	{
321 	}
322 }