/**
* Copyright (c) 2009, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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.synapse.transport.passthru.util;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.transport.MessageFormatter;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.SOAPMessageFormatter;
import org.apache.axis2.util.MessageProcessorSelector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpVersion;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.protocol.HTTP;
import org.apache.synapse.transport.nhttp.NhttpConstants;
import org.apache.synapse.transport.passthru.PassThroughConstants;
import org.apache.synapse.transport.passthru.Pipe;
import org.apache.synapse.transport.passthru.TargetRequest;
import org.apache.synapse.transport.passthru.config.TargetConfiguration;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
//import org.apache.axis2.util.MessageProcessorSelector;
public class TargetRequestFactory {
private static Log log = LogFactory.getLog(TargetRequestFactory.class);
public static TargetRequest create(MessageContext msgContext,
HttpRoute route,
TargetConfiguration configuration) throws AxisFault {
try {
String httpMethod = (String) msgContext.getProperty(
Constants.Configuration.HTTP_METHOD);
if (httpMethod == null) {
httpMethod = "POST";
}
// basic request
Boolean noEntityBody = (Boolean) msgContext.getProperty(PassThroughConstants.NO_ENTITY_BODY);
if(msgContext.getEnvelope().getBody().getFirstElement() != null){
noEntityBody =false;
}
EndpointReference epr = PassThroughTransportUtils.getDestinationEPR(msgContext);
URL url = new URL(epr.getAddress());
TargetRequest request = new TargetRequest(configuration, route, url, httpMethod,
noEntityBody == null || !noEntityBody);
//this code block is needed to replace the host header in service chaining with REQUEST_HOST_HEADER
//adding host header since it is not available in response message.
//otherwise Host header will not replaced after first call
if (msgContext.getProperty(NhttpConstants.REQUEST_HOST_HEADER) != null) {
Object headers = msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
if(headers != null) {
Map headersMap = (Map) headers;
if (!headersMap.containsKey(HTTPConstants.HEADER_HOST)) {
headersMap.put(HTTPConstants.HEADER_HOST
, msgContext.getProperty(NhttpConstants.REQUEST_HOST_HEADER));
}
}
}
// headers
PassThroughTransportUtils.removeUnwantedHeaders(msgContext, configuration);
Object o = msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
if (o != null && o instanceof Map) {
Map headers = (Map) o;
for (Object entryObj : headers.entrySet()) {
Map.Entry entry = (Map.Entry) entryObj;
if (entry.getValue() != null && entry.getKey() instanceof String &&
entry.getValue() instanceof String) {
if (HTTPConstants.HEADER_HOST.equalsIgnoreCase((String) entry.getKey())
&& !configuration.isPreserveHttpHeader(HTTPConstants.HEADER_HOST)) {
if (msgContext.getProperty(NhttpConstants.REQUEST_HOST_HEADER) != null) {
request.addHeader((String) entry.getKey(),
(String) msgContext.getProperty(NhttpConstants.REQUEST_HOST_HEADER));
}
} else {
request.addHeader((String) entry.getKey(), (String) entry.getValue());
}
}
}
}
String cType = getContentType(msgContext, configuration.isPreserveHttpHeader(HTTP.CONTENT_TYPE));
if (cType != null && (!httpMethod.equals("GET") && !httpMethod.equals("DELETE"))) {
String messageType = (String) msgContext.getProperty("messageType");
if (messageType != null) {
boolean builderInvoked = false;
final Pipe pipe = (Pipe) msgContext
.getProperty(PassThroughConstants.PASS_THROUGH_PIPE);
if (pipe != null) {
builderInvoked = Boolean.TRUE.equals(msgContext
.getProperty(PassThroughConstants.MESSAGE_BUILDER_INVOKED));
}
// if multipart related message type and unless if message
// not get build we should
// skip of setting formatter specific content Type
if (messageType.indexOf(HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED) == -1
&& messageType.indexOf(HTTPConstants.MEDIA_TYPE_MULTIPART_FORM_DATA) == -1) {
Map msgCtxheaders = (Map) o;
if (msgCtxheaders != null && !cType.isEmpty()) {
msgCtxheaders.put(HTTP.CONTENT_TYPE, cType);
}
request.addHeader(HTTP.CONTENT_TYPE, cType);
}
// if messageType is related to multipart and if message
// already built we need to set new
// boundary related content type at Content-Type header
if (builderInvoked
&& (((messageType.indexOf(HTTPConstants.MEDIA_TYPE_MULTIPART_RELATED) != -1)
|| (messageType.indexOf(HTTPConstants.MEDIA_TYPE_MULTIPART_FORM_DATA) != -1)))) {
request.addHeader(HTTP.CONTENT_TYPE, cType);
}
} else {
request.addHeader(HTTP.CONTENT_TYPE, cType);
}
}
// version
String forceHttp10 = (String) msgContext.getProperty(PassThroughConstants.FORCE_HTTP_1_0);
if ("true".equals(forceHttp10)) {
request.setVersion(HttpVersion.HTTP_1_0);
}
// keep alive
String noKeepAlie = (String) msgContext.getProperty(PassThroughConstants.NO_KEEPALIVE);
if ("true".equals(noKeepAlie)) {
request.setKeepAlive(false);
}
// port
int port = url.getPort();
request.setPort(port);
// chunk
String disableChunking = (String) msgContext.getProperty(
PassThroughConstants.DISABLE_CHUNKING);
if ("true".equals(disableChunking)) {
request.setChunk(false);
}
// full url
String fullUrl = (String) msgContext.getProperty(PassThroughConstants.FULL_URI);
if ("true".equals(fullUrl)) {
request.setFullUrl(true);
}
// Add excess respsonse header.
String excessProp = NhttpConstants.EXCESS_TRANSPORT_HEADERS;
Map excessHeaders = (Map) msgContext.getProperty(excessProp);
if (excessHeaders != null) {
for (Iterator iterator = excessHeaders.keySet().iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
for (String excessVal : (Collection<String>) excessHeaders.get(key)) {
request.addHeader(key, (String) excessVal);
}
}
}
return request;
} catch (MalformedURLException e) {
handleException("Invalid to address" + msgContext.getTo().getAddress(), e);
}
return null;
}
private static String getContentType(MessageContext msgCtx, boolean isContentTypePreservedHeader) throws AxisFault {
if (isContentTypePreservedHeader) {
if (msgCtx.getProperty(Constants.Configuration.CONTENT_TYPE) != null) {
return (String) msgCtx.getProperty(Constants.Configuration.CONTENT_TYPE);
} else if (msgCtx.getProperty(Constants.Configuration.MESSAGE_TYPE) != null) {
return (String) msgCtx.getProperty(Constants.Configuration.MESSAGE_TYPE);
}
}
MessageFormatter formatter = MessageProcessorSelector.getMessageFormatter(msgCtx);
OMOutputFormat format = PassThroughTransportUtils.getOMOutputFormat(msgCtx);
if (formatter != null) {
String contentType= formatter.getContentType(msgCtx, format, msgCtx.getSoapAction());
//keep the formatter information to prevent multipart boundary override (this will be the content writing to header)
msgCtx.setProperty(PassThroughConstants.MESSAGE_OUTPUT_FORMAT, format);
return contentType;
} else {
String contentType = (String) msgCtx.getProperty(Constants.Configuration.CONTENT_TYPE);
if (contentType != null) {
return contentType;
} else {
return new SOAPMessageFormatter().getContentType(
msgCtx, format, msgCtx.getSoapAction());
}
}
}
/**
* Throws an AxisFault if an error occurs at this level
* @param s a message describing the error
* @param e original exception leads to the error condition
* @throws org.apache.axis2.AxisFault wrapping the original exception
*/
private static void handleException(String s, Exception e) throws AxisFault {
log.error(s, e);
throw new AxisFault(s, e);
}
}