/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.rest.support;
import com.eviware.soapui.impl.rest.RestMethod;
import com.eviware.soapui.impl.rest.RestRepresentation;
import com.eviware.soapui.impl.rest.RestRequestInterface;
import com.eviware.soapui.impl.rest.RestResource;
import com.eviware.soapui.impl.rest.RestService;
import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder.ParameterStyle;
import com.eviware.soapui.impl.support.definition.support.InvalidDefinitionException;
import com.eviware.soapui.impl.wsdl.support.Constants;
import com.eviware.soapui.impl.wsdl.support.UrlSchemaLoader;
import com.eviware.soapui.impl.wsdl.support.xsd.SchemaUtils;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.Tools;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.xml.XmlUtils;
import com.eviware.soapui.tools.PropertyExpansionRemover;
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.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;
import net.java.dev.wadl.x2009.x02.RepresentationDocument.Representation;
import net.java.dev.wadl.x2009.x02.ResourceDocument.Resource;
import net.java.dev.wadl.x2009.x02.ResourceTypeDocument;
import net.java.dev.wadl.x2009.x02.ResourcesDocument.Resources;
import net.java.dev.wadl.x2009.x02.ResponseDocument.Response;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WadlImporter {
private RestService service;
private Application application;
private List<Resources> resourcesList;
private Map<String, ApplicationDocument> refCache = new HashMap<String, ApplicationDocument>();
private boolean isWADL11 = true;
public WadlImporter(RestService service) {
this.service = service;
}
public void initFromWadl(String wadlUrl) {
try {
// XmlObject xmlObject = XmlObject.Factory.parse( new URL( wadlUrl ) );
XmlObject xmlObject = XmlUtils.createXmlObject(new URL(wadlUrl));
String content = xmlObject.xmlText();
Element element = ((Document) xmlObject.getDomNode()).getDocumentElement();
// try to allow older namespaces
if (element.getLocalName().equals("application")
&& element.getNamespaceURI().startsWith("http://research.sun.com/wadl")) {
isWADL11 = false;
content = content.replaceAll("\"" + element.getNamespaceURI() + "\"", "\"" + Constants.WADL11_NS + "\"");
} else if (!element.getLocalName().equals("application")
|| !element.getNamespaceURI().equals(Constants.WADL11_NS)) {
throw new Exception("Document is not a WADL application with " + Constants.WADL11_NS + " namespace");
}
content = PropertyExpansionRemover.removeExpansions(content);
ApplicationDocument applicationDocument = ApplicationDocument.Factory.parse(content);
application = applicationDocument.getApplication();
resourcesList = application.getResourcesList();
service.setName(getFirstTitle(application.getDocList(), service.getName()));
String base = resourcesList.size() == 1 ? resourcesList.get(0).getBase() : "";
try {
URL baseUrl = new URL(base);
service.setBasePath(baseUrl.getPath());
service.addEndpoint(Tools.getEndpointFromUrl(baseUrl));
} catch (Exception e) {
service.setBasePath(base);
}
service.setWadlUrl(wadlUrl);
service.getConfig().setWadlVersion(isWADL11 ? Constants.WADL11_NS : Constants.WADL10_NS);
for (Resources resources : resourcesList) {
RestResource baseResource = null;
if (resourcesList.size() > 1) {
String path = resources.getBase();
baseResource = service.addNewResource(path, path);
}
for (Resource resource : resources.getResourceList()) {
String name = getFirstTitle(resource.getDocList(), resource.getPath());
String path = resource.getPath();
RestResource newResource = null;
if (baseResource != null && path != null) {
for (RestResource res : baseResource.getChildResourceList()) {
if (path.equals(res.getPath())) {
newResource = res;
break;
}
}
if (newResource == null) {
newResource = baseResource.addNewChildResource(name, path);
}
} else if (path != null) {
for (RestResource res : service.getResourceList()) {
if (path.equals(res.getPath())) {
newResource = res;
break;
}
}
if (newResource == null) {
newResource = service.addNewResource(name, path);
}
} else {
newResource = service.addNewResource(name, "");
}
initResourceFromWadlResource(newResource, resource);
addSubResources(newResource, resource);
}
}
} catch (InvalidDefinitionException ex) {
ex.show();
} catch (Exception e) {
UISupport.showErrorMessage(e);
}
}
private void addSubResources(RestResource newResource, Resource resource) {
for (Resource res : resource.getResourceList()) {
String path = res.getPath();
if (path == null) {
path = "";
}
String name = getFirstTitle(res.getDocList(), path);
RestResource newRes = null;
for (RestResource child : newResource.getChildResourceList()) {
if (path.equals(child.getPath())) {
newRes = child;
break;
}
}
if (newRes == null) {
newRes = newResource.addNewChildResource(name, path);
}
initResourceFromWadlResource(newRes, res);
addSubResources(newRes, res);
}
}
private String getFirstTitle(List<Doc> list, String defaultTitle) {
for (Doc doc : list) {
if (StringUtils.hasContent(doc.getTitle())) {
return doc.getTitle();
}
}
return defaultTitle;
}
private void initResourceFromWadlResource(RestResource newResource, Resource resource) {
for (Param param : resource.getParamList()) {
param = resolveParameter(param);
if (param != null) {
String nm = param.getName();
RestParamProperty prop = newResource.hasProperty(nm) ? newResource.getProperty(nm) : newResource
.addProperty(nm);
initParam(param, prop);
}
}
for (Method method : resource.getMethodList()) {
method = resolveMethod(method);
initMethod(newResource, method);
}
List<?> types = resource.getType();
if (types != null && types.size() > 0) {
for (Object obj : types) {
ResourceTypeDocument.ResourceType type = resolveResource(obj.toString());
if (type != null) {
for (Method method : type.getMethodList()) {
method = resolveMethod(method);
RestMethod restMethod = initMethod(newResource, method);
for (Param param : type.getParamList()) {
param = resolveParameter(param);
if (param != null) {
String nm = param.getName();
RestParamProperty prop = restMethod.hasProperty(nm) ? restMethod.getProperty(nm)
: restMethod.addProperty(nm);
initParam(param, prop);
}
}
}
}
}
}
}
private RestMethod initMethod(RestResource newResource, Method method) {
// build name
String name = getFirstTitle(method.getDocList(), method.getName());
String id = method.getId();
if (StringUtils.hasContent(id) && !id.trim().equals(name.trim())) {
name += " - " + method.getId();
}
// ensure unique name
if (newResource.getRestMethodByName(name) != null) {
int cnt = 0;
String orgName = name;
while (newResource.getRestMethodByName(name) != null) {
cnt++;
name = orgName + "-" + cnt;
}
}
// add to resource
RestMethod restMethod = newResource.addNewMethod(name);
restMethod.setMethod(RestRequestInterface.HttpMethod.valueOf(method.getName()));
if (method.getRequest() != null) {
for (Param param : method.getRequest().getParamList()) {
param = resolveParameter(param);
if (param != null) {
RestParamProperty p = restMethod.addProperty(param.getName());
initParam(param, p);
}
}
for (Representation representation : method.getRequest().getRepresentationList()) {
representation = resolveRepresentation(representation);
addRepresentationFromConfig(restMethod, representation, RestRepresentation.Type.REQUEST, null);
}
}
for (Response response : method.getResponseList()) {
for (Representation representation : response.getRepresentationList()) {
addRepresentation(response, restMethod, representation);
}
if (!isWADL11) {
NodeList children = response.getDomNode().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i);
if ("fault".equals(n.getNodeName())) {
String content = XmlUtils.serialize(n, false);
try {
Map<Object, Object> map = new HashMap<Object, Object>();
XmlCursor cursor = response.newCursor();
cursor.getAllNamespaces(map);
cursor.dispose();
XmlOptions options = new XmlOptions();
options.setLoadAdditionalNamespaces(map);
// XmlObject obj = XmlObject.Factory.parse(
// content.replaceFirst( "<(([a-z]+:)?)fault ",
// "<$1representation " ), options );
XmlObject obj = XmlUtils.createXmlObject(
content.replaceFirst("<(([a-z]+:)?)fault ", "<$1representation "), options);
RepresentationDocument representation = (RepresentationDocument) obj
.changeType(RepresentationDocument.type);
addRepresentation(response, restMethod, representation.getRepresentation());
} catch (XmlException e) {
}
}
}
}
}
restMethod.addNewRequest("Request 1");
return restMethod;
}
private void addRepresentation(Response response, RestMethod restMethod, Representation representation) {
representation = resolveRepresentation(representation);
List<Long> status = null;
if (isWADL11) {
status = response.getStatus();
} else {
Node n = representation.getDomNode().getAttributes().getNamedItem("status");
if (n != null) {
status = new ArrayList<Long>();
for (String s : n.getNodeValue().split(" ")) {
status.add(Long.parseLong(s));
}
}
}
boolean fault = false;
if (status != null && status.size() > 0) {
fault = true;
for (Long s : status) {
if (s < 400) {
fault = false;
break;
}
}
}
RestRepresentation.Type type = fault ? RestRepresentation.Type.FAULT : RestRepresentation.Type.RESPONSE;
addRepresentationFromConfig(restMethod, representation, type, status);
}
private void addRepresentationFromConfig(RestMethod restMethod, Representation representation,
RestRepresentation.Type type, List<?> status) {
RestRepresentation restRepresentation = restMethod.addNewRepresentation(type);
restRepresentation.setMediaType(representation.getMediaType());
restRepresentation.setElement(representation.getElement());
if (status != null) {
restRepresentation.setStatus(status);
}
restRepresentation.setId(representation.getId());
restRepresentation.setDescription(getFirstTitle(representation.getDocList(), null));
}
private void initParam(Param param, RestParamProperty prop) {
prop.setDefaultValue(param.getDefault());
prop.setValue(param.getDefault());
ParamStyle.Enum paramStyle = param.getStyle();
if (paramStyle == null) {
paramStyle = ParamStyle.QUERY;
}
prop.setStyle(ParameterStyle.valueOf(paramStyle.toString().toUpperCase()));
prop.setRequired(param.getRequired());
QName paramType = param.getType();
prop.setType(paramType);
String[] options = new String[param.sizeOfOptionArray()];
for (int c = 0; c < options.length; c++) {
options[c] = param.getOptionArray(c).getValue();
}
if (options.length > 0) {
prop.setOptions(options);
}
}
private Method resolveMethod(Method method) {
String href = method.getHref();
if (!StringUtils.hasContent(href)) {
return method;
}
for (Method m : application.getMethodList()) {
if (m.getId().equals(href.substring(1))) {
return m;
}
}
try {
ApplicationDocument applicationDocument = loadReferencedWadl(href);
if (applicationDocument != null) {
int ix = href.lastIndexOf('#');
if (ix > 0) {
href = href.substring(ix + 1);
}
for (Method m : application.getMethodList()) {
if (m.getId().equals(href)) {
return m;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return method;
}
private Representation resolveRepresentation(Representation representation) {
String href = representation.getHref();
if (!StringUtils.hasContent(href)) {
return representation;
}
try {
Application app = application;
if (!href.startsWith("#")) {
ApplicationDocument applicationDocument = loadReferencedWadl(href);
app = applicationDocument.getApplication();
}
if (app != null) {
int ix = href.lastIndexOf('#');
if (ix >= 0) {
href = href.substring(ix + 1);
}
for (Representation m : application.getRepresentationList()) {
if (m.getId().equals(href)) {
return m;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return representation;
}
private Param resolveParameter(Param param) {
String href = param.getHref();
if (!StringUtils.hasContent(href)) {
return param;
}
try {
Application app = application;
if (!href.startsWith("#")) {
ApplicationDocument applicationDocument = loadReferencedWadl(href);
app = applicationDocument.getApplication();
}
if (app != null) {
int ix = href.lastIndexOf('#');
if (ix >= 0) {
href = href.substring(ix + 1);
}
for (Param p : application.getParamList()) {
if (p.getId().equals(href)) {
return p;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/*
* private Representation resolveFault( Representation representation ) {
* String href = representation.getHref(); if( !StringUtils.hasContent( href
* ) ) return representation;
*
* try { ApplicationDocument applicationDocument = loadReferencedWadl( href
* ); if( applicationDocument != null ) { int ix = href.lastIndexOf( '#' );
* if( ix > 0 ) href = href.substring( ix + 1 );
*
* for( Representation m : application.getFaultList() ) { if(
* m.getId().equals( href ) ) return m; } } } catch( Exception e ) {
* e.printStackTrace(); }
*
* return representation; }
*/
private ResourceTypeDocument.ResourceType resolveResource(String id) {
for (ResourceTypeDocument.ResourceType resourceType : application.getResourceTypeList()) {
if (resourceType.getId().equals(id)) {
return resourceType;
}
}
try {
ApplicationDocument applicationDocument = loadReferencedWadl(id);
if (applicationDocument != null) {
int ix = id.lastIndexOf('#');
if (ix > 0) {
id = id.substring(ix + 1);
}
for (ResourceTypeDocument.ResourceType resourceType : applicationDocument.getApplication()
.getResourceTypeList()) {
if (resourceType.getId().equals(id)) {
return resourceType;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private ApplicationDocument loadReferencedWadl(String id) throws URISyntaxException, XmlException, IOException {
int ix = id.indexOf('#');
if (ix != -1) {
id = id.substring(0, ix);
}
ApplicationDocument applicationDocument = refCache.get(id);
if (applicationDocument == null) {
URI uri = new URI(id);
applicationDocument = ApplicationDocument.Factory.parse(uri.toURL());
refCache.put(id, applicationDocument);
}
return applicationDocument;
}
public static Map<String, XmlObject> getDefinitionParts(String wadlUrl) {
Map<String, XmlObject> result = new HashMap<String, XmlObject>();
try {
return SchemaUtils.getSchemas(wadlUrl, new UrlSchemaLoader(wadlUrl));
// URL url = new URL(wadlUrl);
// ApplicationDocument applicationDocument =
// ApplicationDocument.Factory.parse(url);
// result.put(url.getPath(), applicationDocument);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static String extractParams(URL param, RestParamsPropertyHolder params) {
String path = param.getPath();
String[] items = path.split("/");
int templateParamCount = 0;
StringBuffer resultPath = new StringBuffer();
for (int i = 0; i < items.length; i++) {
String item = items[i];
try {
String[] matrixParams = item.split(";");
if (matrixParams.length > 0) {
item = matrixParams[0];
for (int c = 1; c < matrixParams.length; c++) {
String matrixParam = matrixParams[c];
int ix = matrixParam.indexOf('=');
if (ix == -1) {
params.addProperty(URLDecoder.decode(matrixParam, "Utf-8")).setStyle(ParameterStyle.MATRIX);
} else {
String name = matrixParam.substring(0, ix);
RestParamProperty property = params.addProperty(URLDecoder.decode(name, "Utf-8"));
property.setStyle(ParameterStyle.MATRIX);
property.setValue(URLDecoder.decode(matrixParam.substring(ix + 1), "Utf-8"));
}
}
}
Integer.parseInt(item);
RestParamProperty prop = params.addProperty("param" + templateParamCount++);
prop.setStyle(ParameterStyle.TEMPLATE);
prop.setValue(item);
item = "{" + prop.getName() + "}";
} catch (Exception e) {
}
if (StringUtils.hasContent(item)) {
resultPath.append('/').append(item);
}
}
String query = ((URL) param).getQuery();
if (StringUtils.hasContent(query)) {
items = query.split("&");
for (String item : items) {
try {
int ix = item.indexOf('=');
if (ix == -1) {
params.addProperty(URLDecoder.decode(item, "Utf-8")).setStyle(ParameterStyle.QUERY);
} else {
String name = item.substring(0, ix);
RestParamProperty property = params.addProperty(URLDecoder.decode(name, "Utf-8"));
property.setStyle(ParameterStyle.QUERY);
property.setValue(URLDecoder.decode(item.substring(ix + 1), "Utf-8"));
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
return resultPath.toString();
}
}