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.IOException;
16  import java.io.UnsupportedEncodingException;
17  import java.net.URI;
18  import java.net.URISyntaxException;
19  import java.net.URL;
20  import java.net.URLDecoder;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.xmlbeans.XmlCursor;
27  import org.apache.xmlbeans.XmlException;
28  import org.apache.xmlbeans.XmlObject;
29  import org.apache.xmlbeans.XmlOptions;
30  import org.w3c.dom.Document;
31  import org.w3c.dom.Element;
32  import org.w3c.dom.Node;
33  import org.w3c.dom.NodeList;
34  
35  import com.eviware.soapui.impl.rest.RestMethod;
36  import com.eviware.soapui.impl.rest.RestRepresentation;
37  import com.eviware.soapui.impl.rest.RestRequestInterface;
38  import com.eviware.soapui.impl.rest.RestResource;
39  import com.eviware.soapui.impl.rest.RestService;
40  import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder.ParameterStyle;
41  import com.eviware.soapui.impl.wsdl.support.Constants;
42  import com.eviware.soapui.impl.wsdl.support.UrlSchemaLoader;
43  import com.eviware.soapui.impl.wsdl.support.xsd.SchemaUtils;
44  import com.eviware.soapui.support.StringUtils;
45  import com.eviware.soapui.support.Tools;
46  import com.eviware.soapui.support.UISupport;
47  import com.eviware.soapui.support.xml.XmlUtils;
48  
49  import net.java.dev.wadl.x2009.x02.ApplicationDocument;
50  import net.java.dev.wadl.x2009.x02.ParamStyle;
51  import net.java.dev.wadl.x2009.x02.RepresentationDocument;
52  import net.java.dev.wadl.x2009.x02.ResourceTypeDocument;
53  import net.java.dev.wadl.x2009.x02.ApplicationDocument.Application;
54  import net.java.dev.wadl.x2009.x02.DocDocument.Doc;
55  import net.java.dev.wadl.x2009.x02.MethodDocument.Method;
56  import net.java.dev.wadl.x2009.x02.ParamDocument.Param;
57  import net.java.dev.wadl.x2009.x02.RepresentationDocument.Representation;
58  import net.java.dev.wadl.x2009.x02.ResourceDocument.Resource;
59  import net.java.dev.wadl.x2009.x02.ResourcesDocument.Resources;
60  import net.java.dev.wadl.x2009.x02.ResponseDocument.Response;
61  
62  public class WadlImporter
63  {
64  	private RestService service;
65  	private Application application;
66  	private List<Resources> resourcesList;
67  	private Map<String, ApplicationDocument> refCache = new HashMap<String, ApplicationDocument>();
68  	private boolean isWADL11 = true;
69  
70  	public WadlImporter( RestService service )
71  	{
72  		this.service = service;
73  	}
74  
75  	public void initFromWadl( String wadlUrl )
76  	{
77  		try
78  		{
79  			XmlObject xmlObject = XmlObject.Factory.parse( new URL( wadlUrl ) );
80  
81  			Element element = ( ( Document )xmlObject.getDomNode() ).getDocumentElement();
82  
83  			// try to allow older namespaces
84  			if( element.getLocalName().equals( "application" )
85  					&& element.getNamespaceURI().startsWith( "http://research.sun.com/wadl" ) )
86  			{
87  				isWADL11 = false;
88  				String content = xmlObject.xmlText();
89  				content = content.replaceAll( "\"" + element.getNamespaceURI() + "\"", "\"" + Constants.WADL11_NS + "\"" );
90  				xmlObject = ApplicationDocument.Factory.parse( content );
91  			}
92  			else if( !element.getLocalName().equals( "application" )
93  					|| !element.getNamespaceURI().equals( Constants.WADL11_NS ) )
94  			{
95  				throw new Exception( "Document is not a WADL application with " + Constants.WADL11_NS + " namespace" );
96  			}
97  
98  			ApplicationDocument applicationDocument = ( ApplicationDocument )xmlObject
99  					.changeType( ApplicationDocument.type );
100 			application = applicationDocument.getApplication();
101 
102 			resourcesList = application.getResourcesList();
103 
104 			service.setName( getFirstTitle( application.getDocList(), service.getName() ) );
105 
106 			String base = resourcesList.size() == 1 ? resourcesList.get( 0 ).getBase() : "";
107 
108 			try
109 			{
110 				URL baseUrl = new URL( base );
111 				service.setBasePath( baseUrl.getPath() );
112 
113 				service.addEndpoint( Tools.getEndpointFromUrl( baseUrl ) );
114 			}
115 			catch( Exception e )
116 			{
117 				service.setBasePath( base );
118 			}
119 
120 			service.setWadlUrl( wadlUrl );
121 			service.getConfig().setWadlVersion( isWADL11 ? Constants.WADL11_NS : Constants.WADL10_NS );
122 
123 			for( Resources resources : resourcesList )
124 			{
125 				RestResource baseResource = null;
126 				if( resourcesList.size() > 1 )
127 				{
128 					String path = resources.getBase();
129 					baseResource = service.addNewResource( path, path );
130 				}
131 				for( Resource resource : resources.getResourceList() )
132 				{
133 					String name = getFirstTitle( resource.getDocList(), resource.getPath() );
134 					String path = resource.getPath();
135 
136 					RestResource newResource = baseResource == null ? service.addNewResource( name, path ) : baseResource
137 							.addNewChildResource( name, path );
138 					initResourceFromWadlResource( newResource, resource );
139 
140 					addSubResources( newResource, resource );
141 				}
142 			}
143 		}
144 		catch( Exception e )
145 		{
146 			UISupport.showErrorMessage( e );
147 		}
148 	}
149 
150 	private void addSubResources( RestResource newResource, Resource resource )
151 	{
152 		for( Resource res : resource.getResourceList() )
153 		{
154 			String name = getFirstTitle( res.getDocList(), res.getPath() );
155 			String path = res.getPath();
156 
157 			RestResource newRes = newResource.addNewChildResource( name, path );
158 			initResourceFromWadlResource( newRes, res );
159 
160 			addSubResources( newRes, res );
161 		}
162 	}
163 
164 	private String getFirstTitle( List<Doc> list, String defaultTitle )
165 	{
166 		for( Doc doc : list )
167 		{
168 			if( StringUtils.hasContent( doc.getTitle() ) )
169 			{
170 				return doc.getTitle();
171 			}
172 		}
173 		return defaultTitle;
174 	}
175 
176 	private void initResourceFromWadlResource( RestResource newResource, Resource resource )
177 	{
178 		for( Param param : resource.getParamList() )
179 		{
180 			String nm = param.getName();
181 			RestParamProperty prop = newResource.hasProperty( nm ) ? newResource.getProperty( nm ) : newResource
182 					.addProperty( nm );
183 
184 			initParam( param, prop );
185 		}
186 
187 		for( Method method : resource.getMethodList() )
188 		{
189 			method = resolveMethod( method );
190 			initMethod( newResource, method );
191 		}
192 
193 		List types = resource.getType();
194 		if( types != null && types.size() > 0 )
195 		{
196 			for( Object obj : types )
197 			{
198 				ResourceTypeDocument.ResourceType type = resolveResource( obj.toString() );
199 				if( type != null )
200 				{
201 					for( Method method : type.getMethodList() )
202 					{
203 						method = resolveMethod( method );
204 						RestMethod restMethod = initMethod( newResource, method );
205 
206 						for( Param param : type.getParamList() )
207 						{
208 							String nm = param.getName();
209 							RestParamProperty prop = restMethod.hasProperty( nm ) ? restMethod.getProperty( nm ) : restMethod
210 									.addProperty( nm );
211 
212 							initParam( param, prop );
213 						}
214 					}
215 				}
216 			}
217 		}
218 	}
219 
220 	private RestMethod initMethod( RestResource newResource, Method method )
221 	{
222 		String name = method.getName();
223 		if( StringUtils.hasContent( method.getId() ) )
224 			name += " - " + method.getId();
225 
226 		RestMethod restMethod = newResource.addNewMethod( getFirstTitle( method.getDocList(), name ) );
227 		restMethod.setMethod( RestRequestInterface.RequestMethod.valueOf( method.getName() ) );
228 
229 		if( method.getRequest() != null )
230 		{
231 			for( Param param : method.getRequest().getParamList() )
232 			{
233 				RestParamProperty p = restMethod.addProperty( param.getName() );
234 				initParam( param, p );
235 			}
236 
237 			for( Representation representation : method.getRequest().getRepresentationList() )
238 			{
239 				representation = resolveRepresentation( representation );
240 				addRepresentationFromConfig( restMethod, representation, RestRepresentation.Type.REQUEST, null );
241 			}
242 		}
243 
244 		for( Response response : method.getResponseList() )
245 		{
246 			for( Representation representation : response.getRepresentationList() )
247 			{
248 				addRepresentation(response, restMethod, representation);
249 			}
250 			if(!isWADL11)
251 			{
252 				NodeList children = response.getDomNode().getChildNodes();
253 				for(int i=0; i<children.getLength(); i++)
254 				{
255 					Node n = children.item( i );
256 					if( "fault".equals(n.getNodeName()) ) {
257 						String content = XmlUtils.serialize( n, false );
258 						try
259 						{
260 							Map<Object,Object> map = new HashMap<Object, Object>();
261 							XmlCursor cursor = response.newCursor();
262 							cursor.getAllNamespaces( map );
263 							cursor.dispose();
264 							XmlOptions options = new XmlOptions();
265 							options.setLoadAdditionalNamespaces( map );
266 							XmlObject obj = XmlObject.Factory.parse( content.replaceFirst( "<(([a-z]+:)?)fault ", "<$1representation " ), options );
267 							RepresentationDocument representation = ( RepresentationDocument )obj.changeType( RepresentationDocument.type );
268 							addRepresentation(response, restMethod, representation.getRepresentation());
269 						}
270 						catch( XmlException e )
271 						{
272 						}
273 					}
274 				}
275 			}
276 		}
277 
278 		RestRequestInterface request = restMethod.addNewRequest( "Request 1" );
279 
280 		return restMethod;
281 	}
282 	
283 	private void addRepresentation(Response response, RestMethod restMethod, Representation representation)
284 	{
285 		representation = resolveRepresentation( representation );
286 		List<Long> status = null;
287 		if( isWADL11 )
288 			status = response.getStatus();
289 		else
290 		{
291 			Node n = representation.getDomNode().getAttributes().getNamedItem( "status" );
292 			if(n != null)
293 			{
294 				status = new ArrayList<Long>();
295 				for(String s : n.getNodeValue().split( " " ) )
296 				{
297 					status.add( Long.parseLong( s ) );
298 				}
299 			}
300 		}
301 		boolean fault = false;
302 		if(status != null && status.size() > 0)
303 		{
304 			fault = true;
305 			for( Long s : status )
306 			{
307 				if(s < 400)
308 				{
309 					fault = false;
310 					break;
311 				}
312 			}
313 		}
314 		RestRepresentation.Type type = fault ? RestRepresentation.Type.FAULT : RestRepresentation.Type.RESPONSE;
315 		addRepresentationFromConfig( restMethod, representation, type, status );
316 	}
317 
318 	private void addRepresentationFromConfig( RestMethod restMethod, Representation representation,
319 			RestRepresentation.Type type, List<?> status )
320 	{
321 		RestRepresentation restRepresentation = restMethod.addNewRepresentation( type );
322 		restRepresentation.setMediaType( representation.getMediaType() );
323 		restRepresentation.setElement( representation.getElement() );
324 		if( status != null )
325 			restRepresentation.setStatus( status );
326 		restRepresentation.setId( representation.getId() );
327 		restRepresentation.setDescription( getFirstTitle( representation.getDocList(), null ) );
328 	}
329 
330 	private void initParam( Param param, RestParamProperty prop )
331 	{
332 		prop.setDefaultValue( param.getDefault() );
333 		prop.setValue( param.getDefault() );
334 		ParamStyle.Enum paramStyle = param.getStyle();
335 		if( paramStyle == null )
336 			paramStyle = ParamStyle.QUERY;
337 
338 		prop.setStyle( ParameterStyle.valueOf( paramStyle.toString().toUpperCase() ) );
339 		prop.setRequired( param.getRequired() );
340 		prop.setType( param.getType() );
341 
342 		String[] options = new String[param.sizeOfOptionArray()];
343 		for( int c = 0; c < options.length; c++ )
344 			options[c] = param.getOptionArray( c ).getValue();
345 
346 		if( options.length > 0 )
347 			prop.setOptions( options );
348 	}
349 
350 	private Method resolveMethod( Method method )
351 	{
352 		String href = method.getHref();
353 		if( !StringUtils.hasContent( href ) )
354 			return method;
355 
356 		for( Method m : application.getMethodList() )
357 		{
358 			if( m.getId().equals( href.substring( 1 ) ) )
359 				return m;
360 		}
361 
362 		try
363 		{
364 			ApplicationDocument applicationDocument = loadReferencedWadl( href );
365 			if( applicationDocument != null )
366 			{
367 				int ix = href.lastIndexOf( '#' );
368 				if( ix > 0 )
369 					href = href.substring( ix + 1 );
370 
371 				for( Method m : application.getMethodList() )
372 				{
373 					if( m.getId().equals( href ) )
374 						return m;
375 				}
376 			}
377 		}
378 		catch( Exception e )
379 		{
380 			e.printStackTrace();
381 		}
382 
383 		return method;
384 	}
385 
386 	private Representation resolveRepresentation( Representation representation )
387 	{
388 		String href = representation.getHref();
389 		if( !StringUtils.hasContent( href ) )
390 			return representation;
391 
392 		try
393 		{
394 			ApplicationDocument applicationDocument = loadReferencedWadl( href );
395 			if( applicationDocument != null )
396 			{
397 				int ix = href.lastIndexOf( '#' );
398 				if( ix > 0 )
399 					href = href.substring( ix + 1 );
400 
401 				for( Representation m : application.getRepresentationList() )
402 				{
403 					if( m.getId().equals( href ) )
404 						return m;
405 				}
406 			}
407 		}
408 		catch( Exception e )
409 		{
410 			e.printStackTrace();
411 		}
412 
413 		return representation;
414 	}
415 
416 	/*
417 	 * private Representation resolveFault( Representation representation ) {
418 	 * String href = representation.getHref(); if( !StringUtils.hasContent( href
419 	 * ) ) return representation;
420 	 * 
421 	 * try { ApplicationDocument applicationDocument = loadReferencedWadl( href
422 	 * ); if( applicationDocument != null ) { int ix = href.lastIndexOf( '#' );
423 	 * if( ix > 0 ) href = href.substring( ix + 1 );
424 	 * 
425 	 * for( Representation m : application.getFaultList() ) { if(
426 	 * m.getId().equals( href ) ) return m; } } } catch( Exception e ) {
427 	 * e.printStackTrace(); }
428 	 * 
429 	 * return representation; }
430 	 */
431 
432 	private ResourceTypeDocument.ResourceType resolveResource( String id )
433 	{
434 		for( ResourceTypeDocument.ResourceType resourceType : application.getResourceTypeList() )
435 		{
436 			if( resourceType.getId().equals( id ) )
437 				return resourceType;
438 		}
439 
440 		try
441 		{
442 			ApplicationDocument applicationDocument = loadReferencedWadl( id );
443 			if( applicationDocument != null )
444 			{
445 				int ix = id.lastIndexOf( '#' );
446 				if( ix > 0 )
447 					id = id.substring( ix + 1 );
448 
449 				for( ResourceTypeDocument.ResourceType resourceType : applicationDocument.getApplication()
450 						.getResourceTypeList() )
451 				{
452 					if( resourceType.getId().equals( id ) )
453 						return resourceType;
454 				}
455 			}
456 		}
457 		catch( Exception e )
458 		{
459 			e.printStackTrace();
460 		}
461 
462 		return null;
463 	}
464 
465 	private ApplicationDocument loadReferencedWadl( String id ) throws URISyntaxException, XmlException, IOException
466 	{
467 		int ix = id.indexOf( '#' );
468 		if( ix != -1 )
469 			id = id.substring( 0, ix );
470 		ApplicationDocument applicationDocument = refCache.get( id );
471 
472 		if( applicationDocument == null )
473 		{
474 			URI uri = new URI( id );
475 			applicationDocument = ApplicationDocument.Factory.parse( uri.toURL() );
476 			refCache.put( id, applicationDocument );
477 		}
478 
479 		return applicationDocument;
480 	}
481 
482 	public static Map<String, XmlObject> getDefinitionParts( String wadlUrl )
483 	{
484 		Map<String, XmlObject> result = new HashMap<String, XmlObject>();
485 
486 		try
487 		{
488 			return SchemaUtils.getSchemas( wadlUrl, new UrlSchemaLoader( wadlUrl ) );
489 
490 			// URL url = new URL(wadlUrl);
491 			// ApplicationDocument applicationDocument =
492 			// ApplicationDocument.Factory.parse(url);
493 			// result.put(url.getPath(), applicationDocument);
494 		}
495 		catch( Exception e )
496 		{
497 			e.printStackTrace();
498 		}
499 
500 		return result;
501 	}
502 
503 	public static String extractParams( URL param, RestParamsPropertyHolder params )
504 	{
505 		String path = param.getPath();
506 		String[] items = path.split( "/" );
507 
508 		int templateParamCount = 0;
509 		StringBuffer resultPath = new StringBuffer();
510 
511 		for( int i = 0; i < items.length; i++ )
512 		{
513 			String item = items[i];
514 			try
515 			{
516 				String[] matrixParams = item.split( ";" );
517 				if( matrixParams.length > 0 )
518 				{
519 					item = matrixParams[0];
520 					for( int c = 1; c < matrixParams.length; c++ )
521 					{
522 						String matrixParam = matrixParams[c];
523 
524 						int ix = matrixParam.indexOf( '=' );
525 						if( ix == -1 )
526 						{
527 							params.addProperty( URLDecoder.decode( matrixParam, "Utf-8" ) ).setStyle( ParameterStyle.MATRIX );
528 						}
529 						else
530 						{
531 							String name = matrixParam.substring( 0, ix );
532 							RestParamProperty property = params.addProperty( URLDecoder.decode( name, "Utf-8" ) );
533 							property.setStyle( ParameterStyle.MATRIX );
534 							property.setValue( URLDecoder.decode( matrixParam.substring( ix + 1 ), "Utf-8" ) );
535 						}
536 					}
537 				}
538 
539 				Integer.parseInt( item );
540 				RestParamProperty prop = params.addProperty( "param" + templateParamCount++ );
541 				prop.setStyle( ParameterStyle.TEMPLATE );
542 				prop.setValue( item );
543 
544 				item = "{" + prop.getName() + "}";
545 			}
546 			catch( Exception e )
547 			{
548 			}
549 
550 			if( StringUtils.hasContent( item ) )
551 				resultPath.append( '/' ).append( item );
552 		}
553 
554 		String query = ( ( URL )param ).getQuery();
555 		if( StringUtils.hasContent( query ) )
556 		{
557 			items = query.split( "&" );
558 			for( String item : items )
559 			{
560 				try
561 				{
562 					int ix = item.indexOf( '=' );
563 					if( ix == -1 )
564 					{
565 						params.addProperty( URLDecoder.decode( item, "Utf-8" ) ).setStyle( ParameterStyle.QUERY );
566 					}
567 					else
568 					{
569 						String name = item.substring( 0, ix );
570 						RestParamProperty property = params.addProperty( URLDecoder.decode( name, "Utf-8" ) );
571 						property.setStyle( ParameterStyle.QUERY );
572 						property.setValue( URLDecoder.decode( item.substring( ix + 1 ), "Utf-8" ) );
573 					}
574 				}
575 				catch( UnsupportedEncodingException e )
576 				{
577 					e.printStackTrace();
578 				}
579 			}
580 		}
581 
582 		return resultPath.toString();
583 	}
584 }