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;
public class SOAPMapCallingConvention extends SOAPCallingConvention {
protected static final String REQUEST_ENVELOPE = "_envelope";
protected static final String REQUEST_BODY = "_body";
protected static final String REQUEST_FUNCTION = "_function_request";
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<String, Object> backpack = new HashMap<String, Object>();
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"));
}
FunctionRequest functionRequest = readInput(functionElem, functionName, backpack);
return functionRequest;
}
protected FunctionRequest readInput(Element functionElem, String functionName, Map<String, Object> backpack) {
Map<String, String> inputParams = new HashMap<String, String>();
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);
}
protected Element readInputElem(Element inputElem, String functionName, String parent,
Element parentElement, Map<String, String> 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();
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) {
Element middleElement = parentElement.getOwnerDocument().createElement(inputElem.getLocalName());
parentElement.appendChild(middleElement);
for (Element parameterElem : new ElementList(inputElem)) {
readInputElem(parameterElem, functionName, parameterName, middleElement, inputParams);
}
}
} 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);
} else if (hasInputChild) {
Iterator itParamNames = inputParamsSpec.keySet().iterator();
boolean found = false;
while (itParamNames.hasNext() && !found) {
String nextParamName = (String) itParamNames.next();
if (nextParamName.startsWith(fullName + ".")) {
found = true;
}
}
if (found) {
for (Element parameterElem : new ElementList(inputElem)) {
readInputElem(parameterElem, functionName, fullName, null, inputParams);
}
} 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;
} 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<String, Object> backpack)
throws IOException {
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);
String envelopeString = ElementFormatter.format(envelope);
out.write(envelopeString);
out.close();
}
protected Element writeResponse(FunctionResult xinsResult, Map<String, Object> 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);
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) {
} else {
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;
}
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) {
} catch (EntityNotFoundException enfe) {
}
writeOutputParameter(parameterName, parameterValue, response);
}
}
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);
}
}
}
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);
}
}
}
protected void writeOutputDataElement(Map dataSectionSpec, Element dataElement, Element parent) {
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);
}
}
private Element cloneElement(Element element) {
Element result = (Element) element.cloneNode(true);
return result;
}
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);
}
}
}