package org.apache.synapse.commons.builders;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMText;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPBody;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.builder.Builder;
import org.apache.axis2.builder.BuilderUtil;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.AxisBinding;
import org.apache.axis2.description.AxisBindingOperation;
import org.apache.axis2.description.AxisEndpoint;
import org.apache.axis2.description.WSDL20DefaultValueHolder;
import org.apache.axis2.description.WSDL2Constants;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.java.security.AccessController;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.util.URIEncoderDecoder;
import org.apache.axis2.util.MultipleEntryHashMap;
import javax.activation.DataHandler;
import javax.xml.namespace.QName;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.regex.Pattern;
/**
* Synapse specific message builder for "application/x-www-form-urlencoded" content type. This
* builder extends the functionality provided by the Axis2 builder.
*/
public class XFormURLEncodedBuilder implements Builder {
private static final QName XFORM_FIRST_ELEMENT = new QName("xformValues");
public OMElement processDocument(InputStream inputStream, String s,
MessageContext messageContext) throws AxisFault {
// first process the input stream
SOAPEnvelope soapEnv = (SOAPEnvelope) processDocumentWrapper(inputStream, s, messageContext);
// when this is a POST request, if the body of the soap envelope is empty and the parameter
// map is there, build a dummy soap body which contains all the parameters coming in.
SOAPBody body = soapEnv.getBody();
String httpMethod = (String) messageContext.getProperty(HTTPConstants.HTTP_METHOD);
if (body.getFirstElement() == null && HTTPConstants.HTTP_METHOD_POST.equals(httpMethod) &&
messageContext.getProperty(Constants.REQUEST_PARAMETER_MAP) != null) {
MultipleEntryHashMap map = (MultipleEntryHashMap) messageContext
.getProperty(Constants.REQUEST_PARAMETER_MAP);
SOAPFactory soapFactory = getSOAPFactory(messageContext);
OMElement bodyFirstChild = soapFactory
.createOMElement(XFORM_FIRST_ELEMENT, body);
createSOAPMessageWithoutSchema(soapFactory, bodyFirstChild, map);
} else if (body.getFirstElement() != null && "mediate".equals(body.getFirstElement().getLocalName())) {
body.getFirstElement().setLocalName(XFORM_FIRST_ELEMENT.getLocalPart());
}
return soapEnv;
}
/**
* @return Returns the document element.
*/
private OMElement processDocumentWrapper(InputStream inputStream, String contentType,
MessageContext messageContext)
throws AxisFault {
MultipleEntryHashMap parameterMap = new MultipleEntryHashMap();
SOAPFactory soapFactory;
AxisBindingOperation axisBindingOperation =
(AxisBindingOperation) messageContext.getProperty(
Constants.AXIS_BINDING_OPERATION);
String queryParameterSeparator = null;
String templatedPath = null;
if (axisBindingOperation != null) {
queryParameterSeparator = (String) axisBindingOperation
.getProperty(WSDL2Constants.ATTR_WHTTP_QUERY_PARAMETER_SEPARATOR);
templatedPath =
(String) axisBindingOperation.getProperty(WSDL2Constants.ATTR_WHTTP_LOCATION);
}
if (queryParameterSeparator == null) {
queryParameterSeparator =
WSDL20DefaultValueHolder.ATTR_WHTTP_QUERY_PARAMETER_SEPARATOR_DEFAULT;
}
AxisEndpoint axisEndpoint =
(AxisEndpoint) messageContext.getProperty(WSDL2Constants.ENDPOINT_LOCAL_NAME);
if (axisEndpoint != null) {
AxisBinding axisBinding = axisEndpoint.getBinding();
String soapVersion =
(String) axisBinding.getProperty(WSDL2Constants.ATTR_WSOAP_VERSION);
soapFactory = getSOAPFactory(soapVersion);
} else {
soapFactory = getSOAPFactory(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
}
EndpointReference endpointReference = messageContext.getTo();
if (endpointReference == null) {
throw new AxisFault("Cannot create DocumentElement without destination EPR");
}
String requestURL = endpointReference.getAddress();
try {
requestURL = extractParametersUsingHttpLocation(templatedPath, parameterMap,
requestURL,
queryParameterSeparator);
} catch (UnsupportedEncodingException e) {
throw AxisFault.makeFault(e);
}
String query = requestURL;
int index;
if ((index = requestURL.indexOf("?")) > -1) {
query = requestURL.substring(index + 1);
}
extractParametersFromRequest(parameterMap, query, queryParameterSeparator,
(String) messageContext.getProperty(
Constants.Configuration.CHARACTER_SET_ENCODING),
inputStream);
messageContext.setProperty(Constants.REQUEST_PARAMETER_MAP, parameterMap);
return BuilderUtil.buildsoapMessage(messageContext, parameterMap,
soapFactory);
}
private static void createSOAPMessageWithoutSchema(SOAPFactory soapFactory,
OMElement bodyFirstChild,
MultipleEntryHashMap requestParameterMap) {
// first add the parameters in the URL
if (requestParameterMap != null) {
for (Object o : requestParameterMap.keySet()) {
String key = (String) o;
Object value;
while ((value = requestParameterMap.get(key)) != null) {
addRequestParameter(soapFactory, bodyFirstChild, null, key, value);
}
}
}
}
private static void addRequestParameter(SOAPFactory soapFactory,
OMElement bodyFirstChild,
OMNamespace ns,
String key,
Object parameter) {
if (parameter instanceof DataHandler) {
DataHandler dataHandler = (DataHandler)parameter;
OMText dataText = bodyFirstChild.getOMFactory().createOMText(
dataHandler, true);
soapFactory.createOMElement(key, ns, bodyFirstChild).addChild(
dataText);
} else {
String textValue = parameter.toString();
soapFactory.createOMElement(key, ns, bodyFirstChild).setText(
textValue);
}
}
private void extractParametersFromRequest(MultipleEntryHashMap parameterMap,
String query,
String queryParamSeparator,
final String charsetEncoding,
final InputStream inputStream)
throws AxisFault {
if (query != null && !"".equals(query)) {
String parts[] = query.split(queryParamSeparator);
for (String part : parts) {
int separator = part.indexOf("=");
if (separator > 0) {
String value = part.substring(separator + 1);
try {
value = URIEncoderDecoder.decode(value);
} catch (UnsupportedEncodingException e) {
throw AxisFault.makeFault(e);
}
parameterMap.put(replaceInvalidCharacters(part.substring(0, separator)),
value);
}
}
}
if (inputStream != null) {
try {
InputStreamReader inputStreamReader;
try {
inputStreamReader = (InputStreamReader) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws UnsupportedEncodingException {
return new InputStreamReader(inputStream, charsetEncoding);
}
}
);
} catch (PrivilegedActionException e) {
throw (UnsupportedEncodingException) e.getException();
}
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
while (true) {
String line = bufferedReader.readLine();
if (line != null) {
String parts[] = line.split(
WSDL20DefaultValueHolder.ATTR_WHTTP_QUERY_PARAMETER_SEPARATOR_DEFAULT);
for (String part : parts) {
int separator = part.indexOf("=");
String value = part.substring(separator + 1);
parameterMap.put(replaceInvalidCharacters(part.substring(0, separator)),
URIEncoderDecoder.decode(value));
}
} else {
break;
}
}
} catch (IOException e) {
throw AxisFault.makeFault(e);
}
}
}
// "2a" replace with "_JsonReader_PD_2a"
// "$a" replace with "_JsonReader_PS_a"
private String replaceInvalidCharacters(String keyString){
if(Pattern.compile("^[0-9]").matcher(keyString).find()) {
return "_JsonReader_PD_" + keyString;
} else if (keyString.startsWith("$")){
return "_JsonReader_PS_" + keyString.substring(1);
} else
return keyString;
}
private SOAPFactory getSOAPFactory(MessageContext messageContext) throws AxisFault {
SOAPFactory soapFactory;
AxisEndpoint axisEndpoint = (AxisEndpoint) messageContext
.getProperty(WSDL2Constants.ENDPOINT_LOCAL_NAME);
if (axisEndpoint != null) {
AxisBinding axisBinding = axisEndpoint.getBinding();
String soapVersion =
(String) axisBinding.getProperty(WSDL2Constants.ATTR_WSOAP_VERSION);
soapFactory = getSOAPFactory(soapVersion);
} else {
soapFactory = getSOAPFactory(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
}
return soapFactory;
}
private SOAPFactory getSOAPFactory(String nsURI) throws AxisFault {
if (nsURI == null) {
return OMAbstractFactory.getSOAP12Factory();
}
else if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(nsURI)) {
return OMAbstractFactory.getSOAP12Factory();
} else if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(nsURI)) {
return OMAbstractFactory.getSOAP11Factory();
} else {
throw new AxisFault(Messages.getMessage("invalidSOAPversion"));
}
}
private String extractParametersUsingHttpLocation(String templatedPath,
MultipleEntryHashMap parameterMap,
String requestURL,
String queryParameterSeparator)
throws AxisFault, UnsupportedEncodingException {
if (templatedPath != null && !"".equals(templatedPath) && templatedPath.contains("{")) {
StringBuilder pathTemplate = new StringBuilder(templatedPath);
// this will hold the index, from which we need to process the request URI
int startIndex = 0;
int templateStartIndex = 0;
int templateEndIndex = 0;
int indexOfNextConstant = 0;
StringBuilder requestURIBuffer = new StringBuilder(requestURL);
while (startIndex < requestURIBuffer.length()) {
// this will always hold the starting index of a template parameter
templateStartIndex = pathTemplate.indexOf("{", templateStartIndex);
if (templateStartIndex > 0) {
// get the preceding constant part from the template
String constantPart =
pathTemplate.substring(templateEndIndex + 1, templateStartIndex);
constantPart = constantPart.replaceAll("\\{\\{","{");
constantPart = constantPart.replaceAll("}}","}");
// get the index of the end of this template param
templateEndIndex = pathTemplate.indexOf("}", templateStartIndex);
if ((pathTemplate.length() -1) > templateEndIndex && pathTemplate.charAt(templateEndIndex +1) == '}') {
templateEndIndex = pathTemplate.indexOf("}", templateEndIndex +2);
}
String parameterName =
pathTemplate.substring(templateStartIndex + 1, templateEndIndex);
// next try to find the next constant
templateStartIndex = pathTemplate.indexOf("{", templateEndIndex);
if (pathTemplate.charAt(templateStartIndex +1) == '{') {
templateStartIndex = pathTemplate.indexOf("{", templateStartIndex +2);
}
int endIndexOfConstant = requestURIBuffer
.indexOf(constantPart, indexOfNextConstant) + constantPart.length();
if (templateStartIndex == -1) {
if (templateEndIndex == pathTemplate.length() - 1) {
// We may have occations where we have templates of the form foo/{name}.
// In this case the next connstant will be ? and not the
// queryParameterSeparator
indexOfNextConstant =
requestURIBuffer
.indexOf("?", endIndexOfConstant);
if (indexOfNextConstant == -1) {
indexOfNextConstant =
requestURIBuffer
.indexOf(queryParameterSeparator,
endIndexOfConstant);
}
if (indexOfNextConstant > 0) {
addParameterToMap(parameterMap, parameterName,
requestURIBuffer.substring(endIndexOfConstant,
indexOfNextConstant));
return requestURL.substring(indexOfNextConstant);
} else {
addParameterToMap(parameterMap, parameterName,
requestURIBuffer.substring(
endIndexOfConstant));
return "";
}
} else {
constantPart =
pathTemplate.substring(templateEndIndex + 1,
pathTemplate.length());
constantPart = constantPart.replaceAll("\\{\\{","{");
constantPart = constantPart.replaceAll("}}","}");
indexOfNextConstant =
requestURIBuffer.indexOf(constantPart, endIndexOfConstant);
addParameterToMap(parameterMap, parameterName,
requestURIBuffer.substring(
endIndexOfConstant, indexOfNextConstant));
if (requestURIBuffer.length() > indexOfNextConstant + 1) {
return requestURIBuffer.substring(indexOfNextConstant + 1);
}
return "";
}
} else {
// this is the next constant from the template
constantPart =
pathTemplate
.substring(templateEndIndex + 1, templateStartIndex);
constantPart = constantPart.replaceAll("\\{\\{","{");
constantPart = constantPart.replaceAll("}}","}");
indexOfNextConstant =
requestURIBuffer.indexOf(constantPart, endIndexOfConstant);
addParameterToMap(parameterMap, parameterName, requestURIBuffer.substring(
endIndexOfConstant, indexOfNextConstant));
startIndex = indexOfNextConstant;
}
}
}
}
return requestURL;
}
private void addParameterToMap(MultipleEntryHashMap parameterMap, String paramName,
String paramValue)
throws UnsupportedEncodingException, AxisFault {
try {
paramValue = URIEncoderDecoder.decode(paramValue);
} catch (UnsupportedEncodingException e) {
throw AxisFault.makeFault(e);
}
if (paramName.startsWith(WSDL2Constants.TEMPLATE_ENCODE_ESCAPING_CHARACTER)) {
parameterMap.put(paramName.substring(1), paramValue);
} else {
parameterMap.put(paramName, paramValue);
}
}
}