/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details at gnu.org.
*/
package com.eviware.soapui.impl.rest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.java.dev.wadl.x2009.x02.ApplicationDocument;
import net.java.dev.wadl.x2009.x02.ApplicationDocument.Application;
import net.java.dev.wadl.x2009.x02.DocDocument.Doc;
import net.java.dev.wadl.x2009.x02.GrammarsDocument.Grammars;
import net.java.dev.wadl.x2009.x02.MethodDocument.Method;
import net.java.dev.wadl.x2009.x02.ParamDocument.Param;
import net.java.dev.wadl.x2009.x02.ParamStyle;
import net.java.dev.wadl.x2009.x02.RepresentationDocument.Representation;
import net.java.dev.wadl.x2009.x02.RequestDocument.Request;
import net.java.dev.wadl.x2009.x02.ResourceDocument.Resource;
import net.java.dev.wadl.x2009.x02.ResourcesDocument.Resources;
import net.java.dev.wadl.x2009.x02.ResponseDocument.Response;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import com.eviware.soapui.impl.rest.panels.request.inspectors.schema.InferredSchemaManager;
import com.eviware.soapui.impl.rest.support.RestParamProperty;
import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder;
import com.eviware.soapui.impl.wsdl.support.Constants;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.types.StringToStringMap;
import com.eviware.soapui.support.xml.XmlUtils;
public class WadlGenerator
{
private RestService restService;
private boolean isWADL11 = true;
public WadlGenerator( RestService restService )
{
this.restService = restService;
}
public XmlObject generateWadl()
{
ApplicationDocument applicationDocument = ApplicationDocument.Factory.newInstance();
Application application = applicationDocument.addNewApplication();
createDoc( application.addNewDoc(), restService );
Resources resources = application.addNewResources();
// use first endpoint for now -> this should be configurable
String basePath = restService.getBasePath();
String[] endpoints = restService.getEndpoints();
if( endpoints.length > 0 )
basePath = endpoints[0] + basePath;
resources.setBase( basePath );
for( int c = 0; c < restService.getOperationCount(); c++ )
{
resources.addNewResource().set( generateWadlResource( restService.getOperationAt( c ) ) );
}
String[] namespaces = InferredSchemaManager.getInferredSchema( restService ).getNamespaces();
if( namespaces.length > 0 )
{
Grammars grammars = application.addNewGrammars();
for( String namespace : namespaces )
{
grammars.addNewInclude().setHref( InferredSchemaManager.filenameForNamespace( namespace ) );
}
}
if( !isWADL11 )
{
XmlOptions options = new XmlOptions();
StringToStringMap subst = new StringToStringMap();
subst.put( Constants.WADL11_NS, Constants.WADL10_NS );
options.setLoadSubstituteNamespaces( subst );
try
{
// return XmlObject.Factory.parse( applicationDocument.xmlText(),
// options );
return XmlUtils.createXmlObject( applicationDocument.xmlText(), options );
}
catch( XmlException e )
{
e.printStackTrace();
}
}
return applicationDocument;
}
private XmlObject generateWadlResource( RestResource resource )
{
Resource resourceConfig = Resource.Factory.newInstance();
createDoc( resourceConfig.addNewDoc(), resource );
String path = resource.getPath();
if( path.startsWith( "/" ) )
path = path.length() > 1 ? path.substring( 1 ) : "";
resourceConfig.setPath( path );
resourceConfig.setId( resource.getName() );
RestParamsPropertyHolder params = resource.getParams();
for( int c = 0; c < params.size(); c++ )
{
generateParam( resourceConfig.addNewParam(), params.getPropertyAt( c ) );
}
for( int c = 0; c < resource.getChildResourceCount(); c++ )
{
resourceConfig.addNewResource().set( generateWadlResource( resource.getChildResourceAt( c ) ) );
}
for( int c = 0; c < resource.getRestMethodCount(); c++ )
{
RestMethod restMethod = resource.getRestMethodAt( c );
generateWadlMethod( resourceConfig, restMethod );
}
return resourceConfig;
}
private void generateParam( Param paramConfig, RestParamProperty param )
{
paramConfig.setName( param.getName() );
if( StringUtils.hasContent( param.getDefaultValue() ) )
paramConfig.setDefault( param.getDefaultValue() );
paramConfig.setType( param.getType() );
paramConfig.setRequired( param.getRequired() );
paramConfig.setDefault( param.getDefaultValue() );
if( StringUtils.hasContent( param.getDescription() ) )
createDoc( paramConfig.addNewDoc(), param.getName() + " Parameter", param.getDescription() );
String[] options = param.getOptions();
for( String option : options )
paramConfig.addNewOption().setValue( option );
ParamStyle.Enum style = ParamStyle.QUERY;
switch( param.getStyle() )
{
case HEADER :
style = ParamStyle.HEADER;
break;
case MATRIX :
style = ParamStyle.MATRIX;
break;
case PLAIN :
style = ParamStyle.PLAIN;
break;
case TEMPLATE :
style = ParamStyle.TEMPLATE;
break;
}
paramConfig.setStyle( style );
}
private void createDoc( Doc docConfig, ModelItem modelItem )
{
createDoc( docConfig, modelItem.getName(), modelItem.getDescription() );
}
private void createDoc( Doc docConfig, String name, String description )
{
docConfig.setLang( "en" );
docConfig.setTitle( name );
docConfig.getDomNode().appendChild( docConfig.getDomNode().getOwnerDocument().createTextNode( description ) );
}
private void generateWadlMethod( Resource resourceConfig, RestMethod restMethod )
{
Method methodConfig = resourceConfig.addNewMethod();
createDoc( methodConfig.addNewDoc(), restMethod );
methodConfig.setName( restMethod.getMethod().toString() );
methodConfig.setId( restMethod.getName() );
Request requestConfig = methodConfig.addNewRequest();
Map<String, RestParamProperty> defaultParams = new HashMap<String, RestParamProperty>();
for( RestParamProperty defaultParam : restMethod.getResource().getDefaultParams() )
defaultParams.put( defaultParam.getName(), defaultParam );
RestParamsPropertyHolder params = restMethod.getParams();
for( int c = 0; c < params.size(); c++ )
{
RestParamProperty param = params.getPropertyAt( c );
if( !defaultParams.containsKey( param.getName() ) || !param.equals( defaultParams.get( param.getName() ) ) )
generateParam( requestConfig.addNewParam(), param );
}
if( restMethod.hasRequestBody() )
{
for( RestRepresentation representation : restMethod.getRepresentations( RestRepresentation.Type.REQUEST, null ) )
{
generateRepresentation( requestConfig.addNewRepresentation(), representation );
}
}
Map<String, Response> responses = new HashMap<String, Response>();
if( !isWADL11 )
responses.put( null, methodConfig.addNewResponse() );
for( RestRepresentation representation : restMethod.getRepresentations() )
{
Response response;
if( isWADL11 )
{
List<Comparable> status = new ArrayList<Comparable>( ( List<Comparable> )representation.getStatus() );
Collections.sort( status );
StringBuilder statusStrBuilder = new StringBuilder();
for( Object o : status )
statusStrBuilder.append( o ).append( " " );
String statusStr = statusStrBuilder.toString();
if( !responses.containsKey( statusStr ) )
{
response = methodConfig.addNewResponse();
response.setStatus( status );
responses.put( statusStr, response );
}
else
{
response = responses.get( statusStr );
}
}
else
{
response = responses.get( null );
}
Representation representationConfig = response.addNewRepresentation();
generateRepresentation( representationConfig, representation );
if( !isWADL11 && representation.getType() == RestRepresentation.Type.FAULT )
{
Element resp = ( Element )response.getDomNode();
Element rep = ( Element )representationConfig.getDomNode();
Element fault = resp.getOwnerDocument().createElementNS( Constants.WADL11_NS, "fault" );
NamedNodeMap attributes = rep.getAttributes();
for( int i = 0; i < attributes.getLength(); i++ )
{
fault.setAttribute( attributes.item( i ).getNodeName(), attributes.item( i ).getNodeValue() );
}
NodeList children = rep.getChildNodes();
for( int i = 0; i < children.getLength(); i++ )
{
fault.appendChild( children.item( i ) );
}
resp.appendChild( fault );
rep.getParentNode().removeChild( rep );
}
}
}
private void generateRepresentation( Representation representationConfig, RestRepresentation representation )
{
representationConfig.setMediaType( representation.getMediaType() );
if( StringUtils.hasContent( representation.getId() ) )
representationConfig.setId( representation.getId() );
if( !isWADL11 )
{
List<?> status = representation.getStatus();
if( status != null && status.size() > 0 )
{
StringBuilder statusStr = new StringBuilder();
for( Object s : status )
statusStr.append( s ).append( " " );
( ( Element )representationConfig.getDomNode() ).setAttribute( "status", statusStr.toString().trim() );
}
}
if( representation.getElement() != null )
representationConfig.setElement( representation.getElement() );
}
}