All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xins.server.SOAPMapCallingConvention Maven / Gradle / Ivy

The newest version!
/*
 * $Id: SOAPMapCallingConvention.java,v 1.18 2012/03/15 21:07:39 agoubard Exp $
 *
 * See the COPYRIGHT file for redistribution and use restrictions.
 */
package org.xins.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.xins.common.spec.DataSectionElementSpec;
import org.xins.common.spec.EntityNotFoundException;
import org.xins.common.spec.FunctionSpec;
import org.xins.common.spec.InvalidSpecificationException;
import org.xins.common.spec.ParameterSpec;
import org.xins.common.text.ParseException;
import org.xins.common.types.Type;
import org.xins.common.xml.DataElementBuilder;
import org.xins.common.xml.ElementFormatter;
import org.xins.common.xml.ElementList;


/**
 * The SOAP calling convention that tries to map the SOAP request to the
 * parameters of the function. The rules applied for the mapping are the same
 * as for the command wsdl-to-api.
 * 

* Note that by default any SOAP message will be handled by the _xins_soap * calling convention. If you want to use this calling convention you will * need to explicitly have _convention=_xins_soap_map in the URL parameters. *

* This calling convention is easily extendable in order to adapt to the * specificity of your SOAP requests. *

* Here is the mapping for the input: *

    *
  • If the element in the Body ends with 'Request', the function name is * considered to be what is specified before
  • *
  • Otherwise the name of the element is used for the name of the function
  • *
  • Elements in the request are mapped to input parameters if available.
  • *
  • Elements with sub-elements are mapped to input parameters element1.sub-element1... if available.
  • *
  • If no parameter is found, try to find an input data element with the name.
  • *
  • If not found, go to the sub-elements and try to find an input data element with the name.
  • *
  • If not found, skip it. Here it's up to you to override this convention and provide a mapping.
  • *
*

* Here is the mapping for the output: *

    *
  • Response name = function name + "Response"
  • *
  • Output parameters with dots are transformed to XML. * e.g. element1.element2 -> <element1><element2>value</element2></element1>
  • *
  • The data section is not put in the returned XML, only the elements it contains.
  • *
  • Data section element attributes are changed to sub-elements with the * same rule as for output parameters.
  • *
* * @version $Revision: 1.18 $ $Date: 2012/03/15 21:07:39 $ * @author Anthony Goubard * * @since XINS 2.1. */ public class SOAPMapCallingConvention extends SOAPCallingConvention { /** * The key used to store the Envelope element of the request. */ protected static final String REQUEST_ENVELOPE = "_envelope"; /** * The key used to store the Body element of the request. */ protected static final String REQUEST_BODY = "_body"; /** * The key used to store the function element of the request. */ protected static final String REQUEST_FUNCTION = "_function_request"; /** * Creates a new SOAPCallingConvention instance. * * @param api * the API, needed for the SOAP messages, cannot be null. * * @throws IllegalArgumentException * if api == null. */ public SOAPMapCallingConvention(API api) throws IllegalArgumentException { super(api); } protected boolean matches(HttpServletRequest httpRequest) throws Exception { return false; } protected FunctionRequest convertRequestImpl(HttpServletRequest httpRequest) throws InvalidRequestException, FunctionNotSpecifiedException { Map backpack = new HashMap(); Element envelopeElem = parseXMLRequest(httpRequest); String envelopeName = envelopeElem.getLocalName(); if (! envelopeName.equals("Envelope")) { throw new InvalidRequestException("Root element is not a SOAP envelope but \"" + envelopeName + "\"."); } backpack.put(REQUEST_ENVELOPE, cloneElement(envelopeElem)); String functionName; Element functionElem; try { Element bodyElem = new ElementList(envelopeElem, "Body").getUniqueChildElement(); backpack.put(REQUEST_BODY, cloneElement(bodyElem)); functionElem = new ElementList(bodyElem).getUniqueChildElement(); backpack.put(REQUEST_FUNCTION, cloneElement(functionElem)); } catch (ParseException pex) { throw new InvalidRequestException("Incorrect SOAP message.", pex); } String requestName = functionElem.getLocalName(); if (!requestName.endsWith("Request")) { functionName = requestName; } else { functionName = requestName.substring(0, requestName.lastIndexOf("Request")); } backpack.put(BackpackConstants.FUNCTION_NAME, functionName); // Parse the input parameters FunctionRequest functionRequest = readInput(functionElem, functionName, backpack); // If there is information in the SOAP Header that you want to store in // the HTTP request or for input parameters or input data section, // parse the SOAP Header here and fill the functionRequest or httpRequest // with the wanted data. return functionRequest; } /** * Generates the function request based the the SOAP request. * This function will get the XML element in the SOAP request and associate * the values with the input parameter or data section element of the function. * * @param functionElem * the SOAP element of the function request, cannot be null. * @param functionName * the name of the function, cannot be null. * @param backpack * the backpack of this request, cannot be null. * * @return * the function request that will be passed to the XINS function, cannot be null. */ protected FunctionRequest readInput(Element functionElem, String functionName, Map backpack) { Map inputParams = new HashMap(); DataElementBuilder dataSectionBuilder = new DataElementBuilder(); for (Element parameterElem : new ElementList(functionElem)) { try { Element dataElement = readInputElem(parameterElem, functionName, null, null, inputParams); if (dataElement != null) { dataSectionBuilder.addToDataElement(dataElement); } } catch (Exception ex) { Log.log_3571(ex, parameterElem.getTagName(), functionName); } } return new FunctionRequest(functionName, inputParams, dataSectionBuilder.getDataElement(), backpack); } /** * Parses the SOAP request element according to the rules specified in this * class description. * * @param inputElem * the SOAP request element, cannot be null. * * @param functionName * the name of the function, cannot be null. * * @param parent * the name of the super element, can be null. * * @param parentElement * the input data element that is being created, can be null. * * @param inputParams * the Map where the input parameters should be stored, cannot be null. * * @return * the input data element for the FunctionRequest or null if the SOAP * request does not need to create a input data element. * * @throws Exception * if anything goes wrong such specifications not available or incorrect SOAP request. */ protected Element readInputElem(Element inputElem, String functionName, String parent, Element parentElement, Map inputParams) throws Exception { FunctionSpec functionSpec = getAPI().getAPISpecification().getFunction(functionName); Map inputParamsSpec = functionSpec.getInputParameters(); Map inputDataSectionSpec = functionSpec.getInputDataSectionElements(); String parameterName = inputElem.getLocalName(); String fullName = parent == null ? parameterName : parent + "." + parameterName; boolean hasInputChild = !new ElementList(inputElem).isEmpty(); // Fill the attribute of the input data section with the SOAP sub-elements if (parentElement != null) { String parentElementName = parentElement.getLocalName(); if (parentElementName == null) { parentElementName = parentElement.getTagName(); } DataSectionElementSpec elementSpec = (DataSectionElementSpec) inputDataSectionSpec.get(parentElementName); if (elementSpec != null && elementSpec.getAttributes().containsKey(parameterName) && !hasInputChild) { String parameterValue = inputElem.getTextContent(); Type parameterType = elementSpec.getAttribute(parameterName).getType(); parameterValue = soapInputValueTransformation(parameterType, parameterValue); parentElement.setAttribute(parameterName, parameterValue); } else if (elementSpec != null && hasInputChild) { //Add a sub-element Element middleElement = parentElement.getOwnerDocument().createElement(inputElem.getLocalName()); parentElement.appendChild(middleElement); for (Element parameterElem : new ElementList(inputElem)) { // read sub-sub-elements readInputElem(parameterElem, functionName, parameterName, middleElement, inputParams); } } // Simple input parameter that maps } else if (inputParamsSpec.containsKey(fullName) && !hasInputChild) { String parameterValue = inputElem.getTextContent(); Type parameterType = ((ParameterSpec) inputParamsSpec.get(fullName)).getType(); parameterValue = soapInputValueTransformation(parameterType, parameterValue); inputParams.put(fullName, parameterValue); // Element with sub-elements } else if (hasInputChild) { // It can be in the parameters or in the data section Iterator itParamNames = inputParamsSpec.keySet().iterator(); boolean found = false; while (itParamNames.hasNext() && !found) { String nextParamName = (String) itParamNames.next(); if (nextParamName.startsWith(fullName + ".")) { found = true; } } // The sub element match a input parameter if (found) { for (Element parameterElem : new ElementList(inputElem)) { readInputElem(parameterElem, functionName, fullName, null, inputParams); } // The sub element match a input data element } else if (inputDataSectionSpec.containsKey(parameterName)) { Element dataElement = inputElem.getOwnerDocument().createElement(parameterName); for (Element parameterElem : new ElementList(inputElem)) { readInputElem(parameterElem, functionName, null, dataElement, inputParams); } return dataElement; // Ignore this element and go throw the sub-elements } else { for (Element parameterElem : new ElementList(inputElem)) { readInputElem(parameterElem, functionName, parent, null, inputParams); } } } else { Log.log_3570(inputElem.getLocalName(), functionName); } return null; } protected void convertResultImpl(FunctionResult xinsResult, HttpServletResponse httpResponse, Map backpack) throws IOException { // Send the XML output to the stream and flush httpResponse.setContentType(RESPONSE_CONTENT_TYPE); PrintWriter out = httpResponse.getWriter(); if (xinsResult.getErrorCode() != null) { httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } else { httpResponse.setStatus(HttpServletResponse.SC_OK); } Element envelope = writeResponse(xinsResult, backpack); // Write the result to the servlet response String envelopeString = ElementFormatter.format(envelope); out.write(envelopeString); out.close(); } protected Element writeResponse(FunctionResult xinsResult, Map backpack) throws IOException { Element requestEnvelope = (Element) backpack.get(REQUEST_ENVELOPE); String envelopeQualifiedName = requestEnvelope.getPrefix() == null ? "Envelope" : requestEnvelope.getPrefix() + ":Envelope"; Element envelope = ElementFormatter.createMainElementNS(requestEnvelope.getNamespaceURI(), envelopeQualifiedName); copyAttributes(requestEnvelope, envelope); // If you want to write the SOAP Header to the response, do it here Element requestBody = (Element) backpack.get(REQUEST_BODY); String bodyQualifiedName = requestBody.getPrefix() == null ? "Body" : requestBody.getPrefix() + ":Body"; Element body = envelope.getOwnerDocument().createElementNS(requestBody.getNamespaceURI(), bodyQualifiedName); copyAttributes(requestBody, body); envelope.appendChild(body); String functionName = (String) backpack.get(BackpackConstants.FUNCTION_NAME); if (xinsResult.getErrorCode() != null) { //writeFaultSection(functionName, namespaceURI, xinsResult, xmlout); } else { // Write the response start tag Element requestFunction = (Element) backpack.get(REQUEST_FUNCTION); String functionQualifiedName = requestFunction.getPrefix() == null ? functionName + "Response" : requestFunction.getPrefix() + ":" + functionName + "Response"; Element response = envelope.getOwnerDocument().createElementNS(requestFunction.getNamespaceURI(), functionQualifiedName); copyAttributes(requestFunction, response); writeOutputParameters(functionName, xinsResult, response); writeOutputDataSection(functionName, xinsResult, response); body.appendChild(response); } return envelope; } /** * Writes the output parameters to the SOAP XML. * * @param functionName * the name of the function called, cannot be null. * * @param xinsResult * the result of the call to the function, cannot be null. * * @param response * the SOAP response element, cannot be null. */ protected void writeOutputParameters(String functionName, FunctionResult xinsResult, Element response) { Iterator outputParameterNames = xinsResult.getParameters().keySet().iterator(); while (outputParameterNames.hasNext()) { String parameterName = (String) outputParameterNames.next(); String parameterValue = xinsResult.getParameter(parameterName); try { FunctionSpec functionSpec = getAPI().getAPISpecification().getFunction(functionName); Type parameterType = functionSpec.getOutputParameter(parameterName).getType(); parameterValue = soapOutputValueTransformation(parameterType, parameterValue); } catch (InvalidSpecificationException ise) { // keep the old value } catch (EntityNotFoundException enfe) { // keep the old value } writeOutputParameter(parameterName, parameterValue, response); } } /** * Write an output parameter to the SOAP response. * * @param parameterName * the name of the output parameter, cannot be null. * * @param parameterValue * the value of the output parameter, cannot be null. * * @param parent * the parent element to put the created element in, cannot be null. */ protected void writeOutputParameter(String parameterName, String parameterValue, Element parent) { String paramPrefix = parent.getNamespaceURI() == null ? parent.getPrefix() + ":" : ""; if (parameterName.indexOf('.') == -1) { Element paramElem = parent.getOwnerDocument().createElementNS(parent.getNamespaceURI(), paramPrefix + parameterName); paramElem.setTextContent(parameterValue); parent.appendChild(paramElem); } else { String elementName = parameterName.substring(0, parameterName.indexOf('.')); String rest = parameterName.substring(parameterName.indexOf('.') + 1); Element paramElem = null; ElementList paramElemChildren = new ElementList(parent, elementName); if (!paramElemChildren.isEmpty()) { paramElem = paramElemChildren.get(0); writeOutputParameter(rest, parameterValue, paramElem); } else { paramElem = parent.getOwnerDocument().createElementNS(parent.getNamespaceURI(), paramPrefix + elementName); writeOutputParameter(rest, parameterValue, paramElem); parent.appendChild(paramElem); } } } /** * Writes the output data section to the SOAP XML. * * @param functionName * the name of the function called. * * @param xinsResult * the result of the call to the function. * * @param response * the SOAP response element, cannot be null. */ protected void writeOutputDataSection(String functionName, FunctionResult xinsResult, Element response) { Map dataSectionSpec = null; try { FunctionSpec functionSpec = getAPI().getAPISpecification().getFunction(functionName); dataSectionSpec = functionSpec.getOutputDataSectionElements(); } catch (InvalidSpecificationException ise) { } catch (EntityNotFoundException enfe) { } Element dataElement = xinsResult.getDataElement(); if (dataElement != null) { Element importedDataElement = (Element) response.getOwnerDocument().importNode(dataElement, true); for (Element nextDataElement : new ElementList(importedDataElement)) { writeOutputDataElement(dataSectionSpec, nextDataElement, response); } } } /** * Write the given output data element in the SOAP response. * * @param dataSectionSpec * the specification of the output data elements for the function, cannot be null. * * @param dataElement * the data element to tranform as SOAP element, cannot be null. * * @param parent * the parent element to add the created element, cannot be null. */ protected void writeOutputDataElement(Map dataSectionSpec, Element dataElement, Element parent) { // Set a prefix to the data element in order to be copied to the created SOAP element if (parent.getNamespaceURI() == null) { dataElement.setPrefix(parent.getPrefix()); } Element transformedDataElement = soapElementTransformation(dataSectionSpec, false, dataElement, false); parent.appendChild(transformedDataElement); } @Override protected void setDataElementAttribute(Element builder, String attributeName, String attributeValue, String elementNameSpacePrefix) { if (attributeName.indexOf(".") == -1) { Element dataElement = builder.getOwnerDocument().createElementNS(builder.getNamespaceURI(), elementNameSpacePrefix + attributeName); dataElement.setTextContent(attributeValue); builder.appendChild(dataElement); } else { String elementName = attributeName.substring(0, attributeName.indexOf(".")); String rest = attributeName.substring(attributeName.indexOf(".") + 1); Element paramElem = builder.getOwnerDocument().createElementNS(builder.getNamespaceURI(), elementNameSpacePrefix + elementName); writeOutputParameter(rest, attributeValue, paramElem); builder.appendChild(paramElem); } } /** * Utility method that clones an Element without the children. * * @param element * the element to be cloned, cannot be null. * * @return * an element which is identical to the given element but with no sub-elements, never null. */ private Element cloneElement(Element element) { Element result = (Element) element.cloneNode(true); return result; } /** * Utility method that copies the attributes of an element to another element. * Note that the name space URI is not copied. * * @param source * the source element to get the attributes from, cannot be null. * * @param target * the target element to copy the attributes to, cannot be null. */ private void copyAttributes(Element source, Element target) { NamedNodeMap attributes = source.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Attr nextAttribute = (Attr) attributes.item(i); String attrName = nextAttribute.getName(); String attrValue = nextAttribute.getValue(); target.setAttributeNS(nextAttribute.getNamespaceURI(), attrName, attrValue); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy