/* * 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.wsdl.mock; import com.eviware.soapui.SoapUI; import com.eviware.soapui.impl.WsdlInterfaceFactory; import com.eviware.soapui.impl.rest.RestRequestInterface; import com.eviware.soapui.impl.support.definition.export.WsdlDefinitionExporter; import com.eviware.soapui.impl.wsdl.WsdlInterface; import com.eviware.soapui.impl.wsdl.WsdlOperation; import com.eviware.soapui.impl.wsdl.support.soap.SoapUtils; import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils; import com.eviware.soapui.model.iface.Interface; import com.eviware.soapui.model.mock.MockResult; import com.eviware.soapui.model.propertyexpansion.PropertyExpander; import com.eviware.soapui.model.support.AbstractMockDispatcher; import com.eviware.soapui.model.support.ModelSupport; import com.eviware.soapui.support.StringUtils; import com.eviware.soapui.support.Tools; import com.eviware.soapui.support.editor.inspectors.attachments.ContentTypeHandler; import com.eviware.soapui.support.types.StringToStringMap; import com.eviware.soapui.support.xml.XmlUtils; import org.apache.log4j.Logger; import org.xml.sax.InputSource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.wsdl.Definition; import javax.wsdl.Import; import javax.wsdl.factory.WSDLFactory; import javax.wsdl.xml.WSDLWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.util.HashMap; import java.util.Map; public class WsdlMockDispatcher extends AbstractMockDispatcher { private WsdlMockService mockService; private WsdlMockRunContext mockContext; private final Map<String, StringToStringMap> wsdlCache = new HashMap<String, StringToStringMap>(); private final static Logger log = Logger.getLogger(WsdlMockDispatcher.class); public WsdlMockDispatcher(WsdlMockService mockService, WsdlMockRunContext mockContext) { this.mockService = mockService; this.mockContext = mockContext; initWsdlCache(); } private void initWsdlCache() { for (Interface iface : mockService.getMockedInterfaces()) { if (!iface.getInterfaceType().equals(WsdlInterfaceFactory.WSDL_TYPE)) { continue; } try { WsdlDefinitionExporter exporter = new WsdlDefinitionExporter((WsdlInterface) iface); String wsdlPrefix = trimLastSlash(getInterfacePrefix(iface)); StringToStringMap parts = exporter.createFilesForExport(wsdlPrefix + "&part="); for (Map.Entry<String, String> partEntry : parts.entrySet()) { if (partEntry.getKey().toLowerCase().endsWith(".wsdl")) { InputSource inputSource = new InputSource(new StringReader(partEntry.getValue())); String content = WsdlUtils.replacePortEndpoint((WsdlInterface) iface, inputSource, mockService.getLocalMockServiceEndpoint()); if (content != null) { parts.put(partEntry.getKey(), content); } } } wsdlCache.put(iface.getName(), parts); log.info("Mounted WSDL for interface [" + iface.getName() + "] at [" + getOverviewUrl() + "]"); } catch (Exception e) { SoapUI.logError(e); } } } @Override public MockResult dispatchRequest(HttpServletRequest request, HttpServletResponse response) throws DispatchException { Object result = null; try { WsdlMockRequest mockRequest = new WsdlMockRequest(request, response, mockContext); result = mockService.runOnRequestScript(mockContext, mockRequest); if (!(result instanceof MockResult)) { if (mockRequest.getMethod() == RestRequestInterface.HttpMethod.POST) { result = dispatchPostRequest(mockRequest); } else { result = super.dispatchRequest(request, response); } } mockService.runAfterRequestScript(mockContext, (MockResult) result); return (MockResult) result; } catch (Throwable e) { if (e instanceof DispatchException) { throw (DispatchException) e; } else { throw new DispatchException(e); } } finally { mockService.fireOnMockResult(result); } } public MockResult dispatchGetRequest(HttpServletRequest request, HttpServletResponse response) throws DispatchException { try { String qs = request.getQueryString(); if (qs != null && qs.toUpperCase().startsWith("WSDL")) { dispatchWsdlRequest(request, response); } else { String docroot = PropertyExpander.expandProperties(mockContext, mockService.getDocroot()); if (StringUtils.hasContent(docroot)) { try { String pathInfo = request.getPathInfo(); if (pathInfo == null) { pathInfo = ""; } if (mockService.getPath().length() > 1 && pathInfo.startsWith(mockService.getPath())) { pathInfo = pathInfo.substring(mockService.getPath().length()); } String filename = docroot + pathInfo.replace('/', File.separatorChar); File file = new File(filename); if (file.exists()) { returnFile(response, file); } } catch (Throwable e) { throw new DispatchException(e); } } } return null; } catch (Exception e) { throw new DispatchException(e); } } public WsdlMockResult dispatchPostRequest(WsdlMockRequest mockRequest) throws Exception { WsdlMockResult result = null; try { long timestamp = System.currentTimeMillis(); SoapVersion soapVersion = mockRequest.getSoapVersion(); if (soapVersion == null) { throw new DispatchException("Unrecognized SOAP Version"); } String soapAction = mockRequest.getSoapAction(); WsdlOperation operation = null; if (SoapUtils.isSoapFault(mockRequest.getRequestContent(), soapVersion)) { // we should inspect fault detail and try to find matching operation // but not for now.. WsdlMockOperation faultMockOperation = mockService.getFaultMockOperation(); if (faultMockOperation != null) { operation = faultMockOperation.getOperation(); } } else { try { operation = SoapUtils.findOperationForRequest(soapVersion, soapAction, mockRequest.getRequestXmlObject(), mockService.getMockedOperations(), mockService.isRequireSoapVersion(), mockService.isRequireSoapAction(), mockRequest.getRequestAttachments()); } catch (Exception e) { if (mockService.isDispatchResponseMessages()) { try { operation = SoapUtils.findOperationForResponse(soapVersion, soapAction, mockRequest.getRequestXmlObject(), mockService.getMockedOperations(), mockService.isRequireSoapVersion(), mockService.isRequireSoapAction()); if (operation != null) { mockRequest.setResponseMessage(true); } } catch (Exception e2) { throw e; } } else { throw e; } } } if (operation != null) { WsdlMockOperation mockOperation = mockService.getMockOperation(operation); if (mockOperation != null) { long startTime = System.nanoTime(); result = mockOperation.dispatchRequest(mockRequest); if (mockRequest.getHttpRequest() instanceof org.mortbay.jetty.Request) { ((org.mortbay.jetty.Request) mockRequest.getHttpRequest()).setHandled(true); } result.setTimeTaken((System.nanoTime() - startTime) / 1000000); result.setTimestamp(timestamp); addMockResult(result); return result; } else { throw new DispatchException("Failed to find matching operation for request"); } } throw new DispatchException("Missing operation for soapAction [" + soapAction + "] and body element [" + XmlUtils.getQName(mockRequest.getContentElement()) + "] with SOAP Version [" + mockRequest.getSoapVersion() + "]"); } catch (Exception e) { if (e instanceof DispatchException) { throw e; } throw new DispatchException(e); } } public MockResult dispatchHeadRequest(HttpServletRequest request, HttpServletResponse response) throws DispatchException { response.setStatus(HttpServletResponse.SC_OK); return null; } protected void dispatchWsdlRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { if (request.getQueryString().equalsIgnoreCase("WSDL")) { printWsdl(response); return; } String ifaceName = request.getParameter("interface"); WsdlInterface iface = (WsdlInterface) mockService.getProject().getInterfaceByName(ifaceName); if (iface == null) { printInterfaceList(response); return; } StringToStringMap parts = wsdlCache.get(iface.getName()); String part = request.getParameter("part"); String content = StringUtils.isNullOrEmpty(part) ? null : parts.get(part); if (content == null) { printPartList(iface, parts, response); return; } if (content != null) { printOkXmlResult(response, content); } } public void release() { clearResults(); mockContext.clear(); } public void printWsdl(HttpServletResponse response) throws IOException { WsdlInterface[] mockedInterfaces = mockService.getMockedInterfaces(); if (mockedInterfaces.length == 1) { StringToStringMap parts = wsdlCache.get(mockedInterfaces[0].getName()); printOkXmlResult(response, parts.get(parts.get("#root#"))); } else { try { WSDLFactory wsdlFactory = WSDLFactory.newInstance(); Definition def = wsdlFactory.newDefinition(); for (WsdlInterface iface : mockedInterfaces) { StringToStringMap parts = wsdlCache.get(iface.getName()); Import wsdlImport = def.createImport(); wsdlImport.setLocationURI(getInterfacePrefix(iface) + "&part=" + parts.get("#root#")); wsdlImport.setNamespaceURI(WsdlUtils.getTargetNamespace(iface.getWsdlContext().getDefinition())); def.addImport(wsdlImport); } response.setStatus(HttpServletResponse.SC_OK); response.setContentType("text/xml"); response.setCharacterEncoding("UTF-8"); WSDLWriter writer = wsdlFactory.newWSDLWriter(); writer.writeWSDL(def, response.getWriter()); } catch (Exception e) { SoapUI.logError(e); throw new IOException("Failed to create combined WSDL"); } } } public void printOkXmlResult(HttpServletResponse response, String content) throws IOException { response.setStatus(HttpServletResponse.SC_OK); response.setContentType("text/xml"); response.setCharacterEncoding("UTF-8"); response.getWriter().print(content); } public void printPartList(WsdlInterface iface, StringToStringMap parts, HttpServletResponse response) throws IOException { response.setStatus(HttpServletResponse.SC_OK); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.print("<html><body><p>Parts in interface [" + iface.getName() + "]</p><ul>"); for (String key : parts.keySet()) { if (key.equals("#root#")) { continue; } out.print("<li><a href=\""); out.print(getInterfacePrefix(iface) + "&part=" + key); out.print("\">" + key + "</a></li>"); } out.print("</ul></p></body></html>"); } public void printInterfaceList(HttpServletResponse response) throws IOException { response.setStatus(HttpServletResponse.SC_OK); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.print("<html><body><p>Mocked Interfaces in project [" + mockService.getProject().getName() + "]</p><ul>"); for (Interface iface : ModelSupport.getChildren(mockService.getProject(), WsdlInterface.class)) { out.print("<li><a href=\""); out.print(getInterfacePrefix(iface)); out.print("\">" + iface.getName() + "</a></li>"); } out.print("</ul></p></body></html>"); } public void returnFile(HttpServletResponse response, File file) throws FileNotFoundException, IOException { FileInputStream in = new FileInputStream(file); response.setStatus(HttpServletResponse.SC_OK); long length = file.length(); response.setContentLength((int) length); response.setContentType(ContentTypeHandler.getContentTypeFromFilename(file.getName())); Tools.readAndWrite(in, length, response.getOutputStream()); in.close(); } public String getInterfacePrefix(Interface iface) { String wsdlPrefix = getOverviewUrl() + "&interface=" + iface.getName(); return wsdlPrefix; } public String getOverviewUrl() { return mockService.getPath() + "?WSDL"; } private String trimLastSlash(String wsdlPrefix) { int lastSlash = wsdlPrefix.lastIndexOf('/'); if (lastSlash != -1) { return wsdlPrefix.substring(lastSlash + 1); } return wsdlPrefix; } }