View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 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.rest.support;
14  
15  import java.io.File;
16  import java.io.FileOutputStream;
17  import java.io.IOException;
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.LinkedHashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.apache.log4j.Logger;
25  import org.apache.xmlbeans.XmlException;
26  import org.apache.xmlbeans.XmlObject;
27  
28  import com.eviware.soapui.SoapUI;
29  import com.eviware.soapui.config.AttachmentConfig;
30  import com.eviware.soapui.config.CompressedStringConfig;
31  import com.eviware.soapui.config.CredentialsConfig;
32  import com.eviware.soapui.config.HttpRequestConfig;
33  import com.eviware.soapui.config.OldRestRequestConfig;
34  import com.eviware.soapui.config.RestParameterConfig;
35  import com.eviware.soapui.config.RestParametersConfig;
36  import com.eviware.soapui.config.RestRequestConfig;
37  import com.eviware.soapui.config.RestRequestStepConfig;
38  import com.eviware.soapui.config.RestResourceRepresentationConfig;
39  import com.eviware.soapui.config.SettingsConfig;
40  import com.eviware.soapui.config.StringToStringMapConfig;
41  import com.eviware.soapui.config.TestAssertionConfig;
42  import com.eviware.soapui.config.StringToStringMapConfig.Entry;
43  import com.eviware.soapui.impl.rest.RestMethod;
44  import com.eviware.soapui.impl.rest.RestRepresentation;
45  import com.eviware.soapui.impl.rest.RestRequest;
46  import com.eviware.soapui.impl.rest.RestResource;
47  import com.eviware.soapui.impl.rest.RestService;
48  import com.eviware.soapui.impl.rest.RestRequestInterface.RequestMethod;
49  import com.eviware.soapui.impl.wsdl.WsdlProject;
50  import com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep;
51  import com.eviware.soapui.model.iface.Interface;
52  import com.eviware.soapui.model.project.Project;
53  import com.eviware.soapui.model.testsuite.TestProperty;
54  import com.eviware.soapui.support.StringUtils;
55  import com.eviware.soapui.support.UISupport;
56  
57  /***
58   * Convert old-style REST Requests to new ones, creating REST Methods for them
59   * or placing them into existing Methods.
60   * 
61   * @author Dain Nilsson
62   */
63  public class RestRequestConverter
64  {
65  
66  	private static Map<Project, Boolean> autoConvert = new HashMap<Project, Boolean>();
67  	private final static Logger log = Logger.getLogger( RestRequestConverter.class );
68  
69  	public static void convert( RestResource resource, OldRestRequestConfig oldConfig )
70  	{
71  		convert( resource, oldConfig, getMethod( resource, oldConfig.getMethod(), oldConfig.getName() ) );
72  	}
73  
74  	public static RestMethod getMethod( RestResource resource, String methodType, String requestName )
75  	{
76  		WsdlProject project = resource.getService().getProject();
77  		if( !autoConvert.containsKey( project ) )
78  		{
79  			autoConvert
80  					.put(
81  							project,
82  							UISupport
83  									.confirm(
84  											"The model for REST requests has changed slightly,\r\n"
85  													+ "introducing a new REST Method item in-between each REST Resource and Request.\r\n"
86  													+ "Any existing REST Request must now be placed under either an existing Method or a new one, "
87  													+ "either automatically or manually.\r\n\r\nWould You like soapUI to do this automatically using the default values?",
88  											"Update REST model for project: " + project.getName() ) );
89  		}
90  		RestMethod method = null;
91  		List<String> options = new ArrayList<String>();
92  		for( int c = 0; c < resource.getRestMethodCount(); c++ )
93  		{
94  			RestMethod restMethod = resource.getRestMethodAt( c );
95  			if( restMethod.getMethod().toString().equals( methodType ) )
96  				options.add( restMethod.getName() );
97  		}
98  		if( autoConvert.get( project ) )
99  		{
100 			if( options.size() > 0 )
101 			{
102 				method = resource.getRestMethodByName( options.get( 0 ) );
103 				log.info( "Placed request '" + requestName + "' under method '" + method.getName() + "' in Resource '"
104 						+ resource.getName() + "'." );
105 			}
106 			else
107 			{
108 				method = resource.addNewMethod( methodType + " Method" );
109 				method.setMethod( RequestMethod.valueOf( methodType ) );
110 				log.info( "Created new Method for Resource '" + resource.getName() + "'." );
111 			}
112 		}
113 		else
114 		{
115 			options.add( "[Create new REST Method]" );
116 			if( requestName == null )
117 				requestName = "REST Request";
118 			String message = "Select REST Method to place \"" + resource.getName() + " > " + requestName + "\" under.";
119 			Object op = UISupport.prompt( message, "Migrate REST Request", options.toArray() );
120 			if( op != null )
121 			{
122 				int ix = options.indexOf( op );
123 				if( ix != -1 && ix != options.size() - 1 )
124 				{
125 					method = resource.getRestMethodByName( ( String )op );
126 				}
127 			}
128 			else
129 				throw new RestConversionException( "Cannot get RestMethod selection!" );
130 			if( method == null )
131 			{
132 				String name = UISupport.prompt( "Name for REST " + methodType + " Method", "Create new REST Method",
133 						methodType + " Method" );
134 				if( name == null )
135 					throw new RestConversionException( "Cannot get name for RestMethod!" );
136 				method = resource.addNewMethod( name );
137 				method.setMethod( RequestMethod.valueOf( methodType ) );
138 			}
139 		}
140 		return method;
141 	}
142 
143 	public static RestResource resolveResource( RestTestRequestStep requestStep )
144 	{
145 		Map<String, RestResource> options = new LinkedHashMap<String, RestResource>();
146 
147 		WsdlProject project = requestStep.getTestCase().getTestSuite().getProject();
148 		String serviceName = requestStep.getRequestStepConfig().getService();
149 		RestService service = ( RestService )project.getInterfaceByName( serviceName );
150 		if( service != null )
151 		{
152 			addResources( service, options );
153 		}
154 		else
155 		{
156 			for( Interface iface : project.getInterfaceList() )
157 			{
158 				if( iface instanceof RestService )
159 				{
160 					addResources( ( RestService )iface, options );
161 				}
162 			}
163 		}
164 		options.put( "<Delete TestRequest>", null );
165 
166 		String message = "Select a new REST Resource to place TestRequest \"" + requestStep.getName() + "\" under.";
167 		Object op = UISupport.prompt( message, "Missing REST Resource for TestRequest", options.keySet().toArray() );
168 		RestResource resource = options.get( op );
169 
170 		return resource;
171 	}
172 
173 	private static void addResources( RestService service, Map<String, RestResource> list )
174 	{
175 		for( RestResource resource : service.getResources().values() )
176 		{
177 			list.put( service.getName() + " > " + resource.getName(), resource );
178 		}
179 	}
180 
181 	@SuppressWarnings( "deprecation" )
182 	private static void convert( RestResource resource, OldRestRequestConfig oldConfig, RestMethod method )
183 	{
184 
185 		RestRequest request = method.addNewRequest( oldConfig.getName() );
186 
187 		XmlBeansRestParamsTestPropertyHolder params = new XmlBeansRestParamsTestPropertyHolder( null, oldConfig
188 				.getParameters() );
189 		RestParamsPropertyHolder parentParams = method.getOverlayParams();
190 
191 		for( TestProperty prop : params.values() )
192 		{
193 			if( !parentParams.containsKey( prop.getName() ) )
194 			{
195 				method.getParams().addParameter( ( RestParamProperty )prop );
196 			}
197 			request.setPropertyValue( prop.getName(), prop.getValue() );
198 		}
199 		params.release();
200 
201 		boolean exists;
202 		for( RestResourceRepresentationConfig rep : oldConfig.getRepresentationList() )
203 		{
204 			exists = false;
205 			for( RestRepresentation existing : method.getRepresentations( RestRepresentation.Type.valueOf( rep.getType()
206 					.toString() ), rep.getMediaType() ) )
207 			{
208 				if( existing.getElement() == null && rep.getElement() == null
209 						|| existing.getElement().equals( rep.getElement() ) )
210 				{
211 					exists = true;
212 					break;
213 				}
214 			}
215 			if( !exists )
216 			{
217 				RestRepresentation repr = method.addNewRepresentation( RestRepresentation.Type.valueOf( rep.getType()
218 						.toString() ) );
219 				repr.setConfig( ( RestResourceRepresentationConfig )rep.copy() );
220 			}
221 		}
222 
223 		RestRequestConfig newConfig = request.getConfig();
224 
225 		newConfig.setRequest( oldConfig.getRequest() );
226 
227 		for( AttachmentConfig ac : oldConfig.getAttachmentList() )
228 			try
229 			{
230 				if( ac.isSetData() )
231 				{
232 					File temp = File.createTempFile( "pattern", ".suffix" );
233 					temp.deleteOnExit();
234 					FileOutputStream out = new FileOutputStream( temp ) ;
235 					out.write( ac.getData() );
236 					request.attachFile( temp, true );
237 				}
238 				else
239 				{
240 					request.attachFile( new File( ac.getUrl() ), false );
241 				}
242 			}
243 			catch( IOException e )
244 			{
245 				e.printStackTrace();
246 			}
247 		newConfig.setAttachmentArray( oldConfig.getAttachmentArray() );
248 
249 		if( oldConfig.isSetFullPath() )
250 			newConfig.setFullPath( oldConfig.getFullPath() );
251 		if( oldConfig.isSetMediaType() )
252 			newConfig.setMediaType( oldConfig.getMediaType() );
253 		if( oldConfig.isSetPostQueryString() )
254 			newConfig.setPostQueryString( oldConfig.getPostQueryString() );
255 		if( oldConfig.isSetAccept() )
256 			newConfig.setAccept( oldConfig.getAccept() );
257 		if( oldConfig.isSetDescription() )
258 			newConfig.setDescription( oldConfig.getDescription() );
259 		if( oldConfig.isSetId() )
260 			newConfig.setId( oldConfig.getId() );
261 		if( oldConfig.isSetSettings() )
262 			newConfig.setSettings( ( SettingsConfig )oldConfig.getSettings().copy() );
263 		if( oldConfig.isSetSslKeystore() )
264 			newConfig.setSslKeystore( oldConfig.getSslKeystore() );
265 		if( oldConfig.isSetTimestamp() )
266 			newConfig.setTimestamp( oldConfig.getTimestamp() );
267 		if( oldConfig.isSetWadlId() )
268 			newConfig.setWadlId( oldConfig.getWadlId() );
269 		
270 		request.updateConfig( newConfig );
271 
272 	}
273 
274 	public static HttpRequestConfig convert( OldRestRequestConfig old )
275 	{
276 		HttpRequestConfig config = HttpRequestConfig.Factory.newInstance();
277 		config.setAssertionArray( old.getAssertionList().toArray( new TestAssertionConfig[old.sizeOfAssertionArray()] ) );
278 		config.setAttachmentArray( old.getAttachmentList().toArray( new AttachmentConfig[old.sizeOfAttachmentArray()] ) );
279 		XmlObject obj = old.getCredentials();
280 		if( obj != null )
281 			config.setCredentials( ( CredentialsConfig )obj.copy() );
282 		obj = old.getParameters();
283 		if( obj != null )
284 			config.setParameters( ( RestParametersConfig )obj.copy() );
285 
286 		obj = old.getRequest();
287 		if( obj != null )
288 			config.setRequest( ( CompressedStringConfig )obj.copy() );
289 		obj = old.getSettings();
290 		if( obj != null )
291 			config.setSettings( ( SettingsConfig )obj.copy() );
292 		if( old.isSetDescription() )
293 			config.setDescription( old.getDescription() );
294 		config.setEncoding( old.getEncoding() );
295 		config.setEndpoint( old.getEndpoint() );
296 		config.setSslKeystore( old.getSslKeystore() );
297 		if( old.isSetMediaType() )
298 			config.setMediaType( old.getMediaType() );
299 		if( old.isSetMethod() )
300 			config.setMethod( old.getMethod() );
301 		if( old.isSetName() )
302 			config.setName( old.getName() );
303 		if( old.isSetPostQueryString() )
304 			config.setPostQueryString( old.getPostQueryString() );
305 		return config;
306 	}
307 
308 	public static HttpRequestConfig updateIfNeeded( XmlObject config )
309 	{
310 		try
311 		{
312 			if( config instanceof RestRequestStepConfig )
313 		{
314 			return convert( OldRestRequestConfig.Factory.parse( config.selectChildren( "http://eviware.com/soapui/config",
315 					"restRequest" )[0].toString() ) );
316 		}
317 			else
318 			{
319 				return ( HttpRequestConfig )config.changeType( HttpRequestConfig.type );
320 			}
321 		}
322 		catch( XmlException e )
323 		{
324 			return HttpRequestConfig.Factory.newInstance();
325 		}
326 	}
327 
328 	public static class RestConversionException extends RuntimeException
329 	{
330 		public RestConversionException( String message )
331 		{
332 			super( message );
333 		}
334 	}
335 
336 	public static void updateRestTestRequest( RestTestRequestStep restTestRequestStep )
337 	{
338 		try
339 		{
340 			RestRequestStepConfig restRequestStepConfig = ( RestRequestStepConfig )restTestRequestStep.getConfig()
341 					.getConfig();
342 			RestRequestConfig restRequestConfig = restRequestStepConfig.getRestRequest();
343 			OldRestRequestConfig oldConfig = OldRestRequestConfig.Factory.parse( restRequestConfig.toString() );
344 
345 			RestParametersConfig oldParams = oldConfig.getParameters();
346 			if( oldParams != null )
347 			{
348 				StringToStringMapConfig newParams = restRequestConfig.addNewParameters();
349 
350 				for( RestParameterConfig oldParam : oldParams.getParameterList() )
351 				{
352 					if( StringUtils.hasContent( oldParam.getValue() ) )
353 					{
354 						Entry entry = newParams.addNewEntry();
355 						entry.setKey( oldParam.getName() );
356 						entry.setValue( oldParam.getValue() );
357 					}
358 				}
359 
360 				restRequestConfig.getParameters().getDomNode().getParentNode().removeChild(
361 						restRequestConfig.getParameters().getDomNode() );
362 			}
363 		}
364 		catch( XmlException e )
365 		{
366 			SoapUI.logError( e );
367 		}
368 	}
369 }