/* * 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; 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; 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 java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; 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()); } } }