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