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;
14  
15  import java.util.ArrayList;
16  import java.util.Collections;
17  import java.util.HashMap;
18  import java.util.List;
19  import java.util.Map;
20  
21  import org.apache.xmlbeans.XmlException;
22  import org.apache.xmlbeans.XmlObject;
23  import org.apache.xmlbeans.XmlOptions;
24  import org.w3c.dom.Element;
25  import org.w3c.dom.NamedNodeMap;
26  import org.w3c.dom.NodeList;
27  
28  import com.eviware.soapui.impl.rest.panels.request.inspectors.schema.InferredSchemaManager;
29  import com.eviware.soapui.impl.rest.support.RestParamProperty;
30  import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder;
31  import com.eviware.soapui.impl.wsdl.support.Constants;
32  import com.eviware.soapui.model.ModelItem;
33  import com.eviware.soapui.support.StringUtils;
34  import com.eviware.soapui.support.types.StringToStringMap;
35  
36  import net.java.dev.wadl.x2009.x02.ApplicationDocument;
37  import net.java.dev.wadl.x2009.x02.ParamStyle;
38  import net.java.dev.wadl.x2009.x02.ApplicationDocument.Application;
39  import net.java.dev.wadl.x2009.x02.DocDocument.Doc;
40  import net.java.dev.wadl.x2009.x02.GrammarsDocument.Grammars;
41  import net.java.dev.wadl.x2009.x02.MethodDocument.Method;
42  import net.java.dev.wadl.x2009.x02.ParamDocument.Param;
43  import net.java.dev.wadl.x2009.x02.RepresentationDocument.Representation;
44  import net.java.dev.wadl.x2009.x02.RequestDocument.Request;
45  import net.java.dev.wadl.x2009.x02.ResourceDocument.Resource;
46  import net.java.dev.wadl.x2009.x02.ResourcesDocument.Resources;
47  import net.java.dev.wadl.x2009.x02.ResponseDocument.Response;
48  
49  public class WadlGenerator
50  {
51  	private RestService restService;
52  	
53  	private boolean isWADL11 = true;
54  
55  	public WadlGenerator( RestService restService )
56  	{
57  		this.restService = restService;
58  	}
59  
60  	public XmlObject generateWadl()
61  	{
62  		ApplicationDocument applicationDocument = ApplicationDocument.Factory.newInstance();
63  		Application application = applicationDocument.addNewApplication();
64  
65  		createDoc( application.addNewDoc(), restService );
66  
67  		Resources resources = application.addNewResources();
68  
69  		// use first endpoint for now -> this should be configurable
70  		String basePath = restService.getBasePath();
71  		String[] endpoints = restService.getEndpoints();
72  		if( endpoints.length > 0 )
73  			basePath = endpoints[0] + basePath;
74  
75  		resources.setBase( basePath );
76  
77  		for( int c = 0; c < restService.getOperationCount(); c++ )
78  		{
79  			resources.addNewResource().set( generateWadlResource( restService.getOperationAt( c ) ) );
80  		}
81  
82  		String[] namespaces = InferredSchemaManager.getInferredSchema( restService ).getNamespaces();
83  		if( namespaces.length > 0 )
84  		{
85  			Grammars grammars = application.addNewGrammars();
86  			for( String namespace : namespaces )
87  			{
88  				grammars.addNewInclude().setHref( InferredSchemaManager.filenameForNamespace( namespace ) );
89  			}
90  		}
91  		
92  		if(!isWADL11)
93  		{
94  			XmlOptions options = new XmlOptions();
95  			StringToStringMap subst = new StringToStringMap();
96  			subst.put( Constants.WADL11_NS, Constants.WADL10_NS );
97  			options.setLoadSubstituteNamespaces( subst );
98  			try
99  			{
100 				return XmlObject.Factory.parse( applicationDocument.xmlText(), options );
101 			}
102 			catch( XmlException e )
103 			{
104 				e.printStackTrace();
105 			}
106 		}
107 
108 		return applicationDocument;
109 	}
110 
111 	private XmlObject generateWadlResource( RestResource resource )
112 	{
113 		Resource resourceConfig = Resource.Factory.newInstance();
114 		createDoc( resourceConfig.addNewDoc(), resource );
115 		String path = resource.getPath();
116 		if( path.startsWith( "/" ) )
117 			path = path.length() > 1 ? path.substring( 1 ) : "";
118 
119 		resourceConfig.setPath( path );
120 		resourceConfig.setId( resource.getName() );
121 
122 		RestParamsPropertyHolder params = resource.getParams();
123 		for( int c = 0; c < params.size(); c++ )
124 		{
125 			generateParam( resourceConfig.addNewParam(), params.getPropertyAt( c ) );
126 		}
127 
128 		for( int c = 0; c < resource.getChildResourceCount(); c++ )
129 		{
130 			resourceConfig.addNewResource().set( generateWadlResource( resource.getChildResourceAt( c ) ) );
131 		}
132 
133 		for( int c = 0; c < resource.getRestMethodCount(); c++ )
134 		{
135 			RestMethod restMethod = resource.getRestMethodAt( c );
136 			generateWadlMethod( resourceConfig, restMethod );
137 		}
138 
139 		return resourceConfig;
140 	}
141 
142 	private void generateParam( Param paramConfig, RestParamProperty param )
143 	{
144 		paramConfig.setName( param.getName() );
145 
146 		if( StringUtils.hasContent( param.getDefaultValue() ) )
147 			paramConfig.setDefault( param.getDefaultValue() );
148 
149 		paramConfig.setType( param.getType() );
150 		paramConfig.setRequired( param.getRequired() );
151 		paramConfig.setDefault( param.getDefaultValue() );
152 
153 		if( StringUtils.hasContent( param.getDescription() ) )
154 			createDoc( paramConfig.addNewDoc(), param.getName() + " Parameter", param.getDescription() );
155 
156 		String[] options = param.getOptions();
157 		for( String option : options )
158 			paramConfig.addNewOption().setValue( option );
159 
160 		ParamStyle.Enum style = ParamStyle.QUERY;
161 		switch( param.getStyle() )
162 		{
163 		case HEADER :
164 			style = ParamStyle.HEADER;
165 			break;
166 		case MATRIX :
167 			style = ParamStyle.MATRIX;
168 			break;
169 		case PLAIN :
170 			style = ParamStyle.PLAIN;
171 			break;
172 		case TEMPLATE :
173 			style = ParamStyle.TEMPLATE;
174 			break;
175 		}
176 
177 		paramConfig.setStyle( style );
178 	}
179 
180 	private void createDoc( Doc docConfig, ModelItem modelItem )
181 	{
182 		createDoc( docConfig, modelItem.getName(), modelItem.getDescription() );
183 	}
184 
185 	private void createDoc( Doc docConfig, String name, String description )
186 	{
187 		docConfig.setLang( "en" );
188 		docConfig.setTitle( name );
189 		docConfig.getDomNode().appendChild( docConfig.getDomNode().getOwnerDocument().createTextNode( description ) );
190 	}
191 
192 	private void generateWadlMethod( Resource resourceConfig, RestMethod restMethod )
193 	{
194 		Method methodConfig = resourceConfig.addNewMethod();
195 		createDoc( methodConfig.addNewDoc(), restMethod );
196 		methodConfig.setName( restMethod.getMethod().toString() );
197 		methodConfig.setId( restMethod.getName() );
198 		Request requestConfig = methodConfig.addNewRequest();
199 
200 		Map<String, RestParamProperty> defaultParams = new HashMap<String, RestParamProperty>();
201 		for( RestParamProperty defaultParam : restMethod.getResource().getDefaultParams() )
202 			defaultParams.put( defaultParam.getName(), defaultParam );
203 
204 		RestParamsPropertyHolder params = restMethod.getParams();
205 		for( int c = 0; c < params.size(); c++ )
206 		{
207 			RestParamProperty param = params.getPropertyAt( c );
208 			if( !defaultParams.containsKey( param.getName() ) || !param.equals( defaultParams.get( param.getName() ) ) )
209 				generateParam( requestConfig.addNewParam(), param );
210 		}
211 
212 		if( restMethod.hasRequestBody() )
213 		{
214 			for( RestRepresentation representation : restMethod.getRepresentations( RestRepresentation.Type.REQUEST, null ) )
215 			{
216 				generateRepresentation( requestConfig.addNewRepresentation(), representation );
217 			}
218 		}
219 		
220 		Map<String,Response> responses = new HashMap<String, Response>();
221 		if( !isWADL11 )
222 			responses.put( null, methodConfig.addNewResponse() );
223 		for( RestRepresentation representation : restMethod.getRepresentations() )
224 		{
225 			Response response;
226 			if( isWADL11 )
227 			{
228 				List<Comparable> status = new ArrayList<Comparable>((List<Comparable>)representation.getStatus());
229 				Collections.sort( status );
230 				StringBuilder statusStrBuilder = new StringBuilder();
231 				for(Object o : status)
232 					statusStrBuilder.append( o ).append( " " );
233 				String statusStr = statusStrBuilder.toString();
234 				
235 				if(!responses.containsKey( statusStr ))
236 				{
237 					response = methodConfig.addNewResponse();
238 					response.setStatus( status );
239 					responses.put( statusStr, response );
240 				}
241 				else
242 				{
243 					response = responses.get( statusStr );
244 				}
245 			}
246 			else
247 			{
248 				response = responses.get( null );
249 			}
250 			
251 			Representation representationConfig = response.addNewRepresentation();
252 			generateRepresentation( representationConfig, representation );
253 			
254 			if( !isWADL11 && representation.getType() == RestRepresentation.Type.FAULT )
255 			{
256 				Element resp = ( Element )response.getDomNode();
257 				Element rep = ( Element )representationConfig.getDomNode();
258 				Element fault = resp.getOwnerDocument().createElementNS( Constants.WADL11_NS, "fault" );
259 				
260 				NamedNodeMap attributes = rep.getAttributes();
261 				for( int i=0; i<attributes.getLength(); i++)
262 				{
263 					fault.setAttribute( attributes.item( i ).getNodeName(), attributes.item( i ).getNodeValue() );
264 				}
265 				NodeList children = rep.getChildNodes();
266 				for( int i=0; i<children.getLength(); i++ )
267 				{
268 					fault.appendChild( children.item( i ) );
269 				}
270 				
271 				resp.appendChild( fault );
272 				rep.getParentNode().removeChild( rep );
273 			}
274 		}
275 	}
276 
277 	private void generateRepresentation( Representation representationConfig, RestRepresentation representation )
278 	{
279 		representationConfig.setMediaType( representation.getMediaType() );
280 
281 		if( StringUtils.hasContent( representation.getId() ) )
282 			representationConfig.setId( representation.getId() );
283 
284 		if(!isWADL11)
285 		{
286 			List<?> status = representation.getStatus();
287 			if( status != null && status.size() > 0 )
288 			{
289 				StringBuilder statusStr = new StringBuilder();
290 				for( Object s : status )
291 					statusStr.append( s ).append( " " );
292 				( ( Element )representationConfig.getDomNode() ).setAttribute( "status", statusStr.toString().trim() );
293 			}
294 		}
295 
296 		if( representation.getElement() != null )
297 			representationConfig.setElement( representation.getElement() );
298 	}
299 
300 }