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

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

There is a newer version: 3.0
Show newest version
/*
 * $Id: SOAPMapCallingConvention.java,v 1.8 2007/09/18 08:45:06 agoubard Exp $
 *
 * Copyright 2003-2007 Orange Nederland Breedband B.V.
 * See the COPYRIGHT file for redistribution and use restrictions.
 */
package org.xins.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;

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

import org.xins.common.collections.BasicPropertyReader;
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.Element;
import org.xins.common.xml.ElementBuilder;


/**
 * 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.8 $ $Date: 2007/09/18 08:45:06 $ * @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 { Element envelopeElem = parseXMLRequest(httpRequest); if (! envelopeElem.getLocalName().equals("Envelope")) { throw new InvalidRequestException("Root element is not a SOAP envelope but \"" + envelopeElem.getLocalName() + "\"."); } httpRequest.setAttribute(REQUEST_ENVELOPE, cloneElement(envelopeElem)); String functionName; Element functionElem; try { Element bodyElem = envelopeElem.getUniqueChildElement("Body"); httpRequest.setAttribute(REQUEST_BODY, cloneElement(bodyElem)); functionElem = bodyElem.getUniqueChildElement(null); httpRequest.setAttribute(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")); } httpRequest.setAttribute(FUNCTION_NAME, functionName); // Parse the input parameters FunctionRequest functionRequest = readInput(functionElem, functionName); // 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. * * @return * the function request that will be passed to the XINS function, cannot be null. */ protected FunctionRequest readInput(Element functionElem, String functionName) { BasicPropertyReader inputParams = new BasicPropertyReader(); ElementBuilder dataSectionBuilder = new ElementBuilder("data"); Iterator itParameters = functionElem.getChildElements().iterator(); Element parameterElem; while (itParameters.hasNext()) { parameterElem = (Element) itParameters.next(); try { Element dataElement = readInputElem(parameterElem, functionName, null, null, inputParams); if (dataElement != null) { dataSectionBuilder.addChild(dataElement); } } catch (Exception ex) { Log.log_3571(ex, parameterElem.getLocalName(), functionName); } } return new FunctionRequest(functionName, inputParams, dataSectionBuilder.createElement()); } /** * 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 PropertyReader 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, BasicPropertyReader 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; // Fill the attribute of the input data section with the SOAP sub-elements if (parentElement != null) { DataSectionElementSpec elementSpec = (DataSectionElementSpec) inputDataSectionSpec.get(parentElement.getLocalName()); if (elementSpec != null && elementSpec.getAttributes().containsKey(fullName) && inputElem.getChildElements().size() == 0) { String parameterValue = inputElem.getText(); Type parameterType = elementSpec.getAttribute(fullName).getType(); parameterValue = soapInputValueTransformation(parameterType, parameterValue); parentElement.setAttribute(fullName, parameterValue); } else if (elementSpec != null && inputElem.getChildElements().size() > 0) { Iterator itParameters = inputElem.getChildElements().iterator(); while (itParameters.hasNext()) { Element parameterElem = (Element) itParameters.next(); readInputElem(parameterElem, functionName, fullName, parentElement, inputParams); } } // Simple input parameter that maps } else if (inputParamsSpec.containsKey(fullName) && inputElem.getChildElements().size() == 0) { String parameterValue = inputElem.getText(); Type parameterType = ((ParameterSpec) inputParamsSpec.get(fullName)).getType(); parameterValue = soapInputValueTransformation(parameterType, parameterValue); inputParams.set(fullName, parameterValue); // Element with sub-elements } else if (inputElem.getChildElements().size() > 0) { // 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) { Iterator itParameters = inputElem.getChildElements().iterator(); while (itParameters.hasNext()) { Element parameterElem = (Element) itParameters.next(); readInputElem(parameterElem, functionName, fullName, null, inputParams); } // The sub element match a input data element } else if (inputDataSectionSpec.containsKey(parameterName)) { Element dataElement = new Element(parameterName); Iterator itParameters = inputElem.getChildElements().iterator(); while (itParameters.hasNext()) { Element parameterElem = (Element) itParameters.next(); readInputElem(parameterElem, functionName, null, dataElement, inputParams); } return dataElement; // Ignore this element and go throw the sub-elements } else { Iterator itParameters = inputElem.getChildElements().iterator(); while (itParameters.hasNext()) { Element parameterElem = (Element) itParameters.next(); readInputElem(parameterElem, functionName, parent, null, inputParams); } } } else { Log.log_3570(inputElem.getLocalName(), functionName); } return null; } protected void convertResultImpl(FunctionResult xinsResult, HttpServletResponse httpResponse, HttpServletRequest httpRequest) 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(httpRequest, xinsResult); // Write the result to the servlet response out.write(envelope.toString()); out.close(); } protected Element writeResponse(HttpServletRequest httpRequest, FunctionResult xinsResult) throws IOException { Element requestEnvelope = (Element) httpRequest.getAttribute(REQUEST_ENVELOPE); Element envelope = new Element(requestEnvelope.getNamespacePrefix(), requestEnvelope.getNamespaceURI(), "Envelope"); copyAttributes(requestEnvelope, envelope); // If you want to write the SOAP Header to the response, do it here Element requestBody = (Element) httpRequest.getAttribute(REQUEST_BODY); Element body = new Element(requestBody.getNamespacePrefix(), null, "Body"); copyAttributes(requestBody, body); envelope.addChild(body); String functionName = (String) httpRequest.getAttribute(FUNCTION_NAME); if (xinsResult.getErrorCode() != null) { //writeFaultSection(functionName, namespaceURI, xinsResult, xmlout); } else { // Write the response start tag Element requestFunction = (Element) httpRequest.getAttribute(REQUEST_FUNCTION); Element response = new Element(requestFunction.getNamespacePrefix(), requestFunction.getNamespaceURI(), functionName + "Response"); copyAttributes(requestFunction, response); writeOutputParameters(functionName, xinsResult, response); writeOutputDataSection(functionName, xinsResult, response); body.addChild(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().getNames(); 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.getNamespacePrefix() : null; if (parameterName.indexOf('.') == -1) { Element paramElem = new Element(paramPrefix, null, parameterName); paramElem.setText(parameterValue); parent.addChild(paramElem); } else { String elementName = parameterName.substring(0, parameterName.indexOf('.')); String rest = parameterName.substring(parameterName.indexOf('.') + 1); Element paramElem = null; if (parent.getChildElements(elementName).size() > 0) { paramElem = (Element) parent.getChildElements(elementName).get(0); writeOutputParameter(rest, parameterValue, paramElem); } else { paramElem = new Element(paramPrefix, null, elementName); writeOutputParameter(rest, parameterValue, paramElem); parent.addChild(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) { Iterator itDataElements = dataElement.getChildElements().iterator(); while (itDataElements.hasNext()) { Element nextDataElement = (Element) itDataElements.next(); 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.setNamespacePrefix(parent.getNamespacePrefix()); } Element transformedDataElement = soapElementTransformation(dataSectionSpec, false, dataElement, false); parent.addChild(transformedDataElement); } protected void setDataElementAttribute(ElementBuilder builder, String attributeName, String attributeValue, String elementNameSpacePrefix) { if (attributeName.indexOf(".") == -1) { Element dataElement = new Element(elementNameSpacePrefix, null, attributeName); dataElement.setText(attributeValue); builder.addChild(dataElement); } else { String elementName = attributeName.substring(0, attributeName.indexOf(".")); String rest = attributeName.substring(attributeName.indexOf(".") + 1); Element paramElem = new Element(elementNameSpacePrefix, null, elementName); writeOutputParameter(rest, attributeValue, paramElem); builder.addChild(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 = new Element(element.getNamespacePrefix(), element.getNamespaceURI(), element.getLocalName()); copyAttributes(element, result); result.setText(element.getText()); 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) { Iterator itAttributes = source.getAttributeMap().entrySet().iterator(); while (itAttributes.hasNext()) { Map.Entry nextAttribute = (Map.Entry) itAttributes.next(); Element.QualifiedName attrQName = (Element.QualifiedName) nextAttribute.getKey(); String attrValue = (String) nextAttribute.getValue(); if (!"xmlns".equals(attrQName.getNamespacePrefix()) || !attrQName.getLocalName().equals(source.getNamespacePrefix())) { target.setAttribute(attrQName.getNamespacePrefix(), attrQName.getNamespaceURI(), attrQName.getLocalName(), attrValue); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy