| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| *******************************************************************************/ |
| package org.apache.ofbiz.webapp.event; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.StringReader; |
| import java.io.Writer; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.servlet.ServletContext; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| import javax.wsdl.WSDLException; |
| import javax.xml.namespace.QName; |
| import javax.xml.stream.XMLInputFactory; |
| import javax.xml.stream.XMLStreamReader; |
| |
| import org.apache.axiom.om.OMAbstractFactory; |
| import org.apache.axiom.om.OMAttribute; |
| import org.apache.axiom.om.OMElement; |
| import org.apache.axiom.om.OMXMLBuilderFactory; |
| import org.apache.axiom.om.impl.builder.StAXOMBuilder; |
| import org.apache.axiom.soap.SOAPBody; |
| import org.apache.axiom.soap.SOAPEnvelope; |
| import org.apache.axiom.soap.SOAPFactory; |
| import org.apache.axiom.soap.SOAPModelBuilder; |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.UtilGenerics; |
| import org.apache.ofbiz.base.util.UtilProperties; |
| import org.apache.ofbiz.base.util.UtilXml; |
| import org.apache.ofbiz.entity.Delegator; |
| import org.apache.ofbiz.service.DispatchContext; |
| import org.apache.ofbiz.service.GenericServiceException; |
| import org.apache.ofbiz.service.LocalDispatcher; |
| import org.apache.ofbiz.service.ModelService; |
| import org.apache.ofbiz.service.ServiceUtil; |
| import org.apache.ofbiz.service.engine.SoapSerializer; |
| import org.apache.ofbiz.webapp.control.ConfigXMLReader; |
| import org.apache.ofbiz.webapp.control.ConfigXMLReader.Event; |
| import org.apache.ofbiz.webapp.control.ConfigXMLReader.RequestMap; |
| import org.apache.ofbiz.webapp.control.RequestHandler; |
| import org.w3c.dom.Document; |
| |
| /** |
| * SOAPEventHandler - SOAP Event Handler implementation |
| */ |
| public class SOAPEventHandler implements EventHandler { |
| |
| public static final String module = SOAPEventHandler.class.getName(); |
| |
| /** |
| * @see org.apache.ofbiz.webapp.event.EventHandler#init(javax.servlet.ServletContext) |
| */ |
| public void init(ServletContext context) throws EventHandlerException { |
| } |
| |
| /** |
| * @see org.apache.ofbiz.webapp.event.EventHandler#invoke(ConfigXMLReader.Event, ConfigXMLReader.RequestMap, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) |
| */ |
| public String invoke(Event event, RequestMap requestMap, HttpServletRequest request, HttpServletResponse response) throws EventHandlerException { |
| LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); |
| Delegator delegator = (Delegator) request.getAttribute("delegator"); |
| |
| // first check for WSDL request |
| String wsdlReq = request.getParameter("wsdl"); |
| if (wsdlReq == null) { |
| wsdlReq = request.getParameter("WSDL"); |
| } |
| if (wsdlReq != null) { |
| String serviceName = RequestHandler.getOverrideViewUri(request.getPathInfo()); |
| DispatchContext dctx = dispatcher.getDispatchContext(); |
| String locationUri = this.getLocationURI(request); |
| |
| if (serviceName != null) { |
| Document wsdl = null; |
| try { |
| wsdl = dctx.getWSDL(serviceName, locationUri); |
| } catch (GenericServiceException e) { |
| serviceName = null; |
| } catch (WSDLException e) { |
| sendError(response, "Unable to obtain WSDL", serviceName); |
| throw new EventHandlerException("Unable to obtain WSDL", e); |
| } |
| |
| if (wsdl != null) { |
| try { |
| OutputStream os = response.getOutputStream(); |
| response.setContentType("text/xml"); |
| UtilXml.writeXmlDocument(os, wsdl); |
| response.flushBuffer(); |
| } catch (IOException e) { |
| throw new EventHandlerException(e); |
| } |
| return null; |
| } else { |
| sendError(response, "Unable to obtain WSDL", serviceName); |
| throw new EventHandlerException("Unable to obtain WSDL"); |
| } |
| } |
| |
| if (serviceName == null) { |
| try { |
| Writer writer = response.getWriter(); |
| StringBuilder sb = new StringBuilder(); |
| sb.append("<html><head><title>OFBiz SOAP/1.1 Services</title></head>"); |
| sb.append("<body>No such service.").append("<p>Services:<ul>"); |
| |
| for (String scvName: dctx.getAllServiceNames()) { |
| ModelService model = dctx.getModelService(scvName); |
| if (model.export) { |
| sb.append("<li><a href=\"").append(locationUri).append("/").append(model.name).append("?wsdl\">"); |
| sb.append(model.name).append("</a></li>"); |
| } |
| } |
| sb.append("</ul></p></body></html>"); |
| |
| writer.write(sb.toString()); |
| writer.flush(); |
| return null; |
| } catch (Exception e) { |
| sendError(response, "Unable to obtain WSDL", null); |
| throw new EventHandlerException("Unable to obtain WSDL"); |
| } |
| } |
| } |
| |
| // not a wsdl request; invoke the service |
| response.setContentType("text/xml"); |
| |
| // request envelope |
| SOAPEnvelope reqEnv = null; |
| |
| // get the service name and parameters |
| try { |
| InputStream inputStream = (InputStream) request.getInputStream(); |
| SOAPModelBuilder builder = (SOAPModelBuilder) OMXMLBuilderFactory.createSOAPModelBuilder(inputStream, "UTF-8"); |
| reqEnv = (SOAPEnvelope) builder.getDocumentElement(); |
| |
| // log the request message |
| if (Debug.verboseOn()) { |
| try { |
| Debug.logInfo("Request Message:\n" + reqEnv + "\n", module); |
| } catch (Throwable t) { |
| } |
| } |
| } catch (Exception e) { |
| sendError(response, "Problem processing the service", null); |
| throw new EventHandlerException("Cannot get the envelope", e); |
| } |
| |
| Debug.logVerbose("[Processing]: SOAP Event", module); |
| |
| String serviceName = null; |
| try { |
| SOAPBody reqBody = reqEnv.getBody(); |
| validateSOAPBody(reqBody); |
| OMElement serviceElement = reqBody.getFirstElement(); |
| serviceName = serviceElement.getLocalName(); |
| Map<String, Object> parameters = UtilGenerics.cast(SoapSerializer.deserialize(serviceElement.toString(), delegator)); |
| try { |
| // verify the service is exported for remote execution and invoke it |
| ModelService model = dispatcher.getDispatchContext().getModelService(serviceName); |
| |
| if (model == null) { |
| sendError(response, "Problem processing the service", serviceName); |
| Debug.logError("Could not find Service [" + serviceName + "].", module); |
| return null; |
| } |
| |
| if (!model.export) { |
| sendError(response, "Problem processing the service", serviceName); |
| Debug.logError("Trying to call Service [" + serviceName + "] that is not exported.", module); |
| return null; |
| } |
| |
| Map<String, Object> serviceResults = dispatcher.runSync(serviceName, parameters); |
| Debug.logVerbose("[EventHandler] : Service invoked", module); |
| |
| createAndSendSOAPResponse(serviceResults, serviceName, response); |
| |
| } catch (GenericServiceException e) { |
| if (UtilProperties.getPropertyAsBoolean("service", "secureSoapAnswer", true)) { |
| sendError(response, "Problem processing the service, check your parameters.", serviceName); |
| } else { |
| if(e.getMessageList() == null) { |
| sendError(response, e.getMessage(), serviceName); |
| } else { |
| sendError(response, e.getMessageList(), serviceName); |
| } |
| Debug.logError(e, module); |
| return null; |
| } |
| } |
| } catch (Exception e) { |
| sendError(response, e.getMessage(), serviceName); |
| Debug.logError(e, module); |
| return null; |
| } |
| |
| return null; |
| } |
| |
| private void validateSOAPBody(SOAPBody reqBody) throws EventHandlerException { |
| // ensure the SOAPBody contains only one service call request |
| Integer numServiceCallRequests = 0; |
| Iterator<Object> serviceIter = UtilGenerics.cast(reqBody.getChildElements()); |
| while (serviceIter.hasNext()) { |
| numServiceCallRequests++; |
| serviceIter.next(); |
| } |
| if (numServiceCallRequests != 1) { |
| throw new EventHandlerException("One service call expected, but received: " + numServiceCallRequests.toString()); |
| } |
| } |
| |
| private void createAndSendSOAPResponse(Map<String, Object> serviceResults, String serviceName, HttpServletResponse response) throws EventHandlerException { |
| try { |
| // setup the response |
| Debug.logVerbose("[EventHandler] : Setting up response message", module); |
| String xmlResults = SoapSerializer.serialize(serviceResults); |
| //Debug.logInfo("xmlResults ==================" + xmlResults, module); |
| XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(xmlResults)); |
| StAXOMBuilder resultsBuilder = (StAXOMBuilder) OMXMLBuilderFactory.createStAXOMBuilder(OMAbstractFactory.getOMFactory(), reader); |
| OMElement resultSer = resultsBuilder.getDocumentElement(); |
| |
| // create the response soap |
| SOAPFactory factory = OMAbstractFactory.getSOAP11Factory(); |
| SOAPEnvelope resEnv = factory.createSOAPEnvelope(); |
| SOAPBody resBody = factory.createSOAPBody(); |
| OMElement resService = factory.createOMElement(new QName(serviceName + "Response")); |
| resService.addChild(resultSer.getFirstElement()); |
| resBody.addChild(resService); |
| resEnv.addChild(resBody); |
| |
| // The declareDefaultNamespace method doesn't work see (https://issues.apache.org/jira/browse/AXIS2-3156) |
| // so the following doesn't work: |
| // resService.declareDefaultNamespace(ModelService.TNS); |
| // instead, create the xmlns attribute directly: |
| OMAttribute defaultNS = factory.createOMAttribute("xmlns", null, ModelService.TNS); |
| resService.addAttribute(defaultNS); |
| |
| // log the response message |
| if (Debug.verboseOn()) { |
| try { |
| Debug.logInfo("Response Message:\n" + resEnv + "\n", module); |
| } catch (Throwable t) { |
| } |
| } |
| |
| resEnv.serialize(response.getOutputStream()); |
| response.getOutputStream().flush(); |
| } catch (Exception e) { |
| Debug.logError(e, module); |
| throw new EventHandlerException(e.getMessage(), e); |
| } |
| } |
| |
| private void sendError(HttpServletResponse res, String errorMessage, String serviceName) throws EventHandlerException { |
| // setup the response |
| sendError(res, ServiceUtil.returnError(errorMessage), serviceName); |
| } |
| |
| private void sendError(HttpServletResponse res, List<String> errorMessages, String serviceName) throws EventHandlerException { |
| sendError(res, ServiceUtil.returnError(errorMessages.toString()), serviceName); |
| } |
| private void sendError(HttpServletResponse res, Object object, String serviceName) throws EventHandlerException { |
| try { |
| // setup the response |
| res.setContentType("text/xml"); |
| String xmlResults= SoapSerializer.serialize(object); |
| XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(xmlResults)); |
| StAXOMBuilder resultsBuilder = (StAXOMBuilder) OMXMLBuilderFactory.createStAXOMBuilder(OMAbstractFactory.getOMFactory(), xmlReader); |
| OMElement resultSer = resultsBuilder.getDocumentElement(); |
| |
| // create the response soap |
| SOAPFactory factory = OMAbstractFactory.getSOAP11Factory(); |
| SOAPEnvelope resEnv = factory.createSOAPEnvelope(); |
| SOAPBody resBody = factory.createSOAPBody(); |
| OMElement errMsg = factory.createOMElement(new QName((serviceName != null ? serviceName : "") + "Response")); |
| errMsg.addChild(resultSer.getFirstElement()); |
| resBody.addChild(errMsg); |
| resEnv.addChild(resBody); |
| |
| // The declareDefaultNamespace method doesn't work see (https://issues.apache.org/jira/browse/AXIS2-3156) |
| // so the following doesn't work: |
| // resService.declareDefaultNamespace(ModelService.TNS); |
| // instead, create the xmlns attribute directly: |
| OMAttribute defaultNS = factory.createOMAttribute("xmlns", null, ModelService.TNS); |
| errMsg.addAttribute(defaultNS); |
| |
| // log the response message |
| if (Debug.verboseOn()) { |
| try { |
| Debug.logInfo("Response Message:\n" + resEnv + "\n", module); |
| } catch (Throwable t) { |
| } |
| } |
| |
| resEnv.serialize(res.getOutputStream()); |
| res.getOutputStream().flush(); |
| } catch (Exception e) { |
| throw new EventHandlerException(e.getMessage(), e); |
| } |
| } |
| |
| private String getLocationURI(HttpServletRequest request) { |
| StringBuilder uri = new StringBuilder(); |
| uri.append(request.getScheme()); |
| uri.append("://"); |
| uri.append(request.getServerName()); |
| if (request.getServerPort() != 80 && request.getServerPort() != 443) { |
| uri.append(":"); |
| uri.append(request.getServerPort()); |
| } |
| uri.append(request.getContextPath()); |
| uri.append(request.getServletPath()); |
| |
| String reqInfo = RequestHandler.getRequestUri(request.getPathInfo()); |
| if (!reqInfo.startsWith("/")) { |
| reqInfo = "/" + reqInfo; |
| } |
| |
| uri.append(reqInfo); |
| return uri.toString(); |
| } |
| } |