/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.camel.component.cxf;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.security.auth.Subject;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.ws.Holder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.component.cxf.common.header.CxfHeaderHelper;
import org.apache.camel.component.cxf.common.message.CxfConstants;
import org.apache.camel.component.cxf.util.ReaderInputStream;
import org.apache.camel.impl.DefaultAttachment;
import org.apache.camel.spi.HeaderFilterStrategy;
import org.apache.camel.spi.HeaderFilterStrategyAware;
import org.apache.camel.util.ExchangeHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.cxf.attachment.AttachmentImpl;
import org.apache.cxf.binding.soap.Soap11;
import org.apache.cxf.binding.soap.Soap12;
import org.apache.cxf.binding.soap.SoapBindingConstants;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.helpers.HttpHeaderHelper;
import org.apache.cxf.jaxws.context.WrappedMessageContext;
import org.apache.cxf.message.Attachment;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.message.MessageUtils;
import org.apache.cxf.security.LoginSecurityContext;
import org.apache.cxf.security.SecurityContext;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.invoker.MethodDispatcher;
import org.apache.cxf.service.model.BindingMessageInfo;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.staxutils.StaxUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Default CXF binding implementation.
*
* @version
*/
public class DefaultCxfBinding implements CxfBinding, HeaderFilterStrategyAware {
private static final Logger LOG = LoggerFactory.getLogger(DefaultCxfBinding.class);
private HeaderFilterStrategy headerFilterStrategy;
// CxfBinding Methods
// -------------------------------------------------------------------------
/**
* This method is called by {@link CxfProducer#process(Exchange)}. It populates
* the CXF exchange and invocation context (i.e. request/response) contexts, it
* but does not create and populate a CXF message as a ClientImpl's invoke method
* will create a new CXF Message. That method will put all properties from the
* CXF exchange and request context to the CXF message.
*/
public void populateCxfRequestFromExchange(
org.apache.cxf.message.Exchange cxfExchange, Exchange camelExchange,
Map<String, Object> requestContext) {
// propagate request context
Map<String, Object> camelHeaders = camelExchange.getIn().getHeaders();
extractInvocationContextFromCamel(camelExchange, camelHeaders,
requestContext, Client.REQUEST_CONTEXT);
// propagate headers
propagateHeadersFromCamelToCxf(camelExchange, camelHeaders, cxfExchange,
requestContext);
String overrideAddress = camelExchange.getIn().getHeader(Exchange.DESTINATION_OVERRIDE_URL, String.class);
if (overrideAddress != null) {
LOG.trace("Client address is overridden by header '{}' to value '{}'",
Exchange.DESTINATION_OVERRIDE_URL, overrideAddress);
requestContext.put(Message.ENDPOINT_ADDRESS, overrideAddress);
}
// propagate attachments
Set<Attachment> attachments = null;
boolean isXop = Boolean.valueOf(camelExchange.getProperty(Message.MTOM_ENABLED, String.class));
DataFormat dataFormat = camelExchange.getProperty(CxfConstants.DATA_FORMAT_PROPERTY,
DataFormat.class);
// we should avoid adding the attachments if the data format is CXFMESSAGE, as the message stream
// already has the attachment information
if (!DataFormat.CXF_MESSAGE.equals(dataFormat)) {
for (Map.Entry<String, org.apache.camel.Attachment> entry : camelExchange.getIn().getAttachmentObjects().entrySet()) {
if (attachments == null) {
attachments = new HashSet<Attachment>();
}
AttachmentImpl attachment = new AttachmentImpl(entry.getKey());
org.apache.camel.Attachment camelAttachment = entry.getValue();
attachment.setDataHandler(camelAttachment.getDataHandler());
for (String name : camelAttachment.getHeaderNames()) {
attachment.setHeader(name, camelAttachment.getHeader(name));
}
attachment.setXOP(isXop);
attachments.add(attachment);
}
}
if (attachments != null) {
requestContext.put(CxfConstants.CAMEL_CXF_ATTACHMENTS, attachments);
}
}
/**
* This method is called by {@link CxfProducer#process(Exchange)}. It propagates
* information from CXF Exchange to Camel Exchange. The CXF Exchange contains a
* request from a CXF server.
*/
public void populateExchangeFromCxfResponse(Exchange camelExchange,
org.apache.cxf.message.Exchange cxfExchange,
Map<String, Object> responseContext) {
Message cxfMessage = cxfExchange.getInMessage();
// Need to check if the inMessage is set
if (cxfMessage == null) {
return;
}
LOG.trace("Populate exchange from CXF response message: {}", cxfMessage);
// copy the InMessage header to OutMessage header
camelExchange.getOut().getHeaders().putAll(camelExchange.getIn().getHeaders());
// propagate body
String encoding = (String)camelExchange.getProperty(Exchange.CHARSET_NAME);
camelExchange.getOut().setBody(DefaultCxfBinding.getContentFromCxf(cxfMessage,
camelExchange.getProperty(CxfConstants.DATA_FORMAT_PROPERTY, DataFormat.class), encoding));
// propagate response context
if (responseContext != null && responseContext.size() > 0) {
if (!headerFilterStrategy.applyFilterToExternalHeaders(Client.RESPONSE_CONTEXT,
responseContext, camelExchange)) {
camelExchange.getOut().setHeader(Client.RESPONSE_CONTEXT, responseContext);
LOG.trace("Set header = {} value = {}", Client.RESPONSE_CONTEXT, responseContext);
}
}
// propagate protocol headers
propagateHeadersFromCxfToCamel(cxfMessage, camelExchange.getOut(), camelExchange);
// propagate attachments
if (cxfMessage.getAttachments() != null) {
// propagate attachments
for (Attachment attachment : cxfMessage.getAttachments()) {
camelExchange.getOut().addAttachmentObject(attachment.getId(), createCamelAttachment(attachment));
}
}
}
private DefaultAttachment createCamelAttachment(Attachment attachment) {
DefaultAttachment camelAttachment = new DefaultAttachment(attachment.getDataHandler());
Iterator<String> headers = attachment.getHeaderNames();
while (headers.hasNext()) {
String name = headers.next();
camelAttachment.addHeader(name, attachment.getHeader(name));
}
return camelAttachment;
}
/**
* This method is called by {@link CxfConsumer}.
*/
public void populateExchangeFromCxfRequest(org.apache.cxf.message.Exchange cxfExchange,
Exchange camelExchange) {
Method method = null;
QName operationName = null;
ExchangePattern mep = ExchangePattern.InOut;
// extract binding operation information
BindingOperationInfo boi = camelExchange.getProperty(BindingOperationInfo.class.getName(),
BindingOperationInfo.class);
if (boi != null) {
Service service = cxfExchange.get(Service.class);
if (service != null) {
MethodDispatcher md = (MethodDispatcher)service.get(MethodDispatcher.class.getName());
if (md != null) {
method = md.getMethod(boi);
}
}
if (boi.getOperationInfo().isOneWay()) {
mep = ExchangePattern.InOnly;
}
operationName = boi.getName();
}
// set operation name in header
if (operationName != null) {
camelExchange.getIn().setHeader(CxfConstants.OPERATION_NAMESPACE,
boi.getName().getNamespaceURI());
camelExchange.getIn().setHeader(CxfConstants.OPERATION_NAME,
boi.getName().getLocalPart());
if (LOG.isTraceEnabled()) {
LOG.trace("Set IN header: {}={}",
CxfConstants.OPERATION_NAMESPACE, boi.getName().getNamespaceURI());
LOG.trace("Set IN header: {}={}",
CxfConstants.OPERATION_NAME, boi.getName().getLocalPart());
}
} else if (method != null) {
camelExchange.getIn().setHeader(CxfConstants.OPERATION_NAME, method.getName());
if (LOG.isTraceEnabled()) {
LOG.trace("Set IN header: {}={}",
CxfConstants.OPERATION_NAME, method.getName());
}
}
// set message exchange pattern
camelExchange.setPattern(mep);
LOG.trace("Set exchange MEP: {}", mep);
// propagate headers
Message cxfMessage = cxfExchange.getInMessage();
propagateHeadersFromCxfToCamel(cxfMessage, camelExchange.getIn(), camelExchange);
// propagate the security subject from CXF security context
SecurityContext securityContext = cxfMessage.get(SecurityContext.class);
if (securityContext instanceof LoginSecurityContext
&& ((LoginSecurityContext)securityContext).getSubject() != null) {
camelExchange.getIn().getHeaders().put(Exchange.AUTHENTICATION,
((LoginSecurityContext)securityContext).getSubject());
} else if (securityContext != null) {
Principal user = securityContext.getUserPrincipal();
if (user != null) {
Subject subject = new Subject();
subject.getPrincipals().add(user);
camelExchange.getIn().getHeaders().put(Exchange.AUTHENTICATION, subject);
}
}
// Propagating properties from CXF Exchange to Camel Exchange has an
// side effect of copying reply side stuff when the producer is retried.
// So, we do not want to do this.
//camelExchange.getProperties().putAll(cxfExchange);
// propagate request context
Object value = cxfMessage.get(Client.REQUEST_CONTEXT);
if (value != null && !headerFilterStrategy.applyFilterToExternalHeaders(
Client.REQUEST_CONTEXT, value, camelExchange)) {
camelExchange.getIn().setHeader(Client.REQUEST_CONTEXT, value);
LOG.trace("Populate context from CXF message {} value={}", Client.REQUEST_CONTEXT, value);
}
// setup the charset from content-type header
setCharsetWithContentType(camelExchange);
// set body
String encoding = (String)camelExchange.getProperty(Exchange.CHARSET_NAME);
Object body = DefaultCxfBinding.getContentFromCxf(cxfMessage,
camelExchange.getProperty(CxfConstants.DATA_FORMAT_PROPERTY, DataFormat.class), encoding);
if (body != null) {
camelExchange.getIn().setBody(body);
}
// propagate attachments if the data format is not POJO
if (cxfMessage.getAttachments() != null
&& !camelExchange.getProperty(CxfConstants.DATA_FORMAT_PROPERTY, DataFormat.class).equals(DataFormat.POJO)) {
for (Attachment attachment : cxfMessage.getAttachments()) {
camelExchange.getIn().addAttachmentObject(attachment.getId(), createCamelAttachment(attachment));
}
}
}
/**
* This method is called by {@link CxfConsumer} to populate a CXF response exchange
* from a Camel exchange.
*/
public void populateCxfResponseFromExchange(Exchange camelExchange,
org.apache.cxf.message.Exchange cxfExchange) {
if (cxfExchange.isOneWay()) {
return;
}
// create response context
Map<String, Object> responseContext = new HashMap<String, Object>();
org.apache.camel.Message response;
if (camelExchange.getPattern().isOutCapable()) {
if (camelExchange.hasOut()) {
response = camelExchange.getOut();
LOG.trace("Get the response from the out message");
} else { // Take the in message as a fall back
response = camelExchange.getIn();
LOG.trace("Get the response from the in message as a fallback");
}
} else {
response = camelExchange.getIn();
LOG.trace("Get the response from the in message");
}
// propagate response context
Map<String, Object> camelHeaders = response.getHeaders();
extractInvocationContextFromCamel(camelExchange, camelHeaders,
responseContext, Client.RESPONSE_CONTEXT);
propagateHeadersFromCamelToCxf(camelExchange, camelHeaders, cxfExchange,
responseContext);
// create out message
Endpoint ep = cxfExchange.get(Endpoint.class);
Message outMessage = ep.getBinding().createMessage();
cxfExchange.setOutMessage(outMessage);
DataFormat dataFormat = camelExchange.getProperty(CxfConstants.DATA_FORMAT_PROPERTY,
DataFormat.class);
// make sure the "requestor role" property does not get propagated as we do switch role
responseContext.remove(Message.REQUESTOR_ROLE);
outMessage.putAll(responseContext);
// Do we still need to put the response context back like this
outMessage.put(Client.RESPONSE_CONTEXT, responseContext);
LOG.trace("Set out response context = {}", responseContext);
// set body
Object outBody = DefaultCxfBinding.getBodyFromCamel(response, dataFormat);
if (outBody != null) {
if (dataFormat == DataFormat.PAYLOAD) {
CxfPayload<?> payload = (CxfPayload<?>)outBody;
outMessage.setContent(List.class, getResponsePayloadList(cxfExchange, payload.getBodySources()));
outMessage.put(Header.HEADER_LIST, payload.getHeaders());
} else {
if (responseContext.get(Header.HEADER_LIST) != null) {
outMessage.put(Header.HEADER_LIST, responseContext.get(Header.HEADER_LIST));
}
MessageContentsList resList = null;
// Create a new MessageContentsList to avoid OOM from the HolderOutInterceptor
if (outBody instanceof List) {
resList = new MessageContentsList((List<?>)outBody);
} else if (outBody.getClass().isArray()) {
resList = new MessageContentsList((Object[])outBody);
} else {
resList = new MessageContentsList(outBody);
}
if (resList != null) {
outMessage.setContent(List.class, resList);
LOG.trace("Set Out CXF message content = {}", resList);
}
}
} else if (!cxfExchange.isOneWay()
&& cxfExchange.getInMessage() != null
&& MessageUtils.isTrue(cxfExchange.getInMessage().getContextualProperty("jaxws.provider.interpretNullAsOneway"))) {
// treat this non-oneway call as oneway when the provider returns a null
changeToOneway(cxfExchange);
return;
}
// propagate attachments
Set<Attachment> attachments = null;
boolean isXop = Boolean.valueOf(camelExchange.getProperty(Message.MTOM_ENABLED, String.class));
for (Map.Entry<String, org.apache.camel.Attachment> entry : camelExchange.getOut().getAttachmentObjects().entrySet()) {
if (attachments == null) {
attachments = new HashSet<Attachment>();
}
AttachmentImpl attachment = new AttachmentImpl(entry.getKey());
org.apache.camel.Attachment camelAttachment = entry.getValue();
attachment.setDataHandler(camelAttachment.getDataHandler());
for (String name : camelAttachment.getHeaderNames()) {
attachment.setHeader(name, camelAttachment.getHeader(name));
}
attachment.setXOP(isXop);
attachments.add(attachment);
}
if (attachments != null) {
outMessage.setAttachments(attachments);
}
BindingOperationInfo boi = cxfExchange.get(BindingOperationInfo.class);
if (boi != null) {
cxfExchange.put(BindingMessageInfo.class, boi.getOutput());
}
}
// HeaderFilterStrategyAware Methods
// -------------------------------------------------------------------------
protected void setCharsetWithContentType(Exchange camelExchange) {
// setup the charset from content-type header
String contentTypeHeader = ExchangeHelper.getContentType(camelExchange);
if (contentTypeHeader != null) {
String charset = HttpHeaderHelper.findCharset(contentTypeHeader);
String normalizedEncoding = HttpHeaderHelper.mapCharset(charset, Charset.forName("UTF-8").name());
if (normalizedEncoding != null) {
camelExchange.setProperty(Exchange.CHARSET_NAME, normalizedEncoding);
}
}
}
public HeaderFilterStrategy getHeaderFilterStrategy() {
return headerFilterStrategy;
}
public void setHeaderFilterStrategy(HeaderFilterStrategy strategy) {
this.headerFilterStrategy = strategy;
}
// Non public methods
// -------------------------------------------------------------------------
protected MessageContentsList getResponsePayloadList(org.apache.cxf.message.Exchange exchange,
List<Source> elements) {
BindingOperationInfo boi = exchange.getBindingOperationInfo();
if (boi.isUnwrapped()) {
boi = boi.getWrappedOperation();
exchange.put(BindingOperationInfo.class, boi);
}
MessageContentsList answer = new MessageContentsList();
int i = 0;
if (boi.getOutput() != null) {
for (MessagePartInfo partInfo : boi.getOutput().getMessageParts()) {
if (elements != null && elements.size() > i) {
answer.put(partInfo, elements.get(i++));
}
}
}
return answer;
}
/**
* @param camelExchange
* @param cxfContext Request or Response context
* @param camelHeaders
* @param contextKey
*/
@SuppressWarnings("unchecked")
protected void extractInvocationContextFromCamel(Exchange camelExchange,
Map<String, Object> camelHeaders, Map<String, Object> cxfContext,
String contextKey) {
// extract from header
Map<String, ?> context = (Map<String, ?>)camelHeaders.get(contextKey);
if (context != null) {
cxfContext.putAll(context);
if (LOG.isTraceEnabled()) {
LOG.trace("Propagate {} from header context = {}",
contextKey, (context instanceof WrappedMessageContext)
? ((WrappedMessageContext)context).getWrappedMap()
: context);
}
}
// extract from exchange property
context = (Map<String, ?>)camelExchange.getProperty(contextKey);
if (context != null) {
cxfContext.putAll(context);
if (LOG.isTraceEnabled()) {
LOG.trace("Propagate {} from exchange property context = {}",
contextKey, (context instanceof WrappedMessageContext)
? ((WrappedMessageContext)context).getWrappedMap()
: context);
}
}
// copy camel exchange properties into context
if (camelExchange.getProperties() != null) {
cxfContext.putAll(camelExchange.getProperties());
}
camelExchange.setProperty(contextKey, cxfContext);
}
/**
* @param cxfMessage
* @param camelMessage
* @param exchange provides context for filtering
*/
protected void propagateHeadersFromCxfToCamel(Message cxfMessage,
org.apache.camel.Message camelMessage, Exchange exchange) {
Map<String, List<String>> cxfHeaders = CastUtils.cast((Map<?, ?>)cxfMessage.get(Message.PROTOCOL_HEADERS));
Map<String, Object> camelHeaders = camelMessage.getHeaders();
camelHeaders.put(CxfConstants.CAMEL_CXF_MESSAGE, cxfMessage);
// Copy the http header to CAMEL as we do in camel-cxfrs
CxfHeaderHelper.copyHttpHeadersFromCxfToCamel(headerFilterStrategy, cxfMessage, camelMessage, exchange);
if (cxfHeaders != null) {
for (Map.Entry<String, List<String>> entry : cxfHeaders.entrySet()) {
if (!headerFilterStrategy.applyFilterToExternalHeaders(entry.getKey(),
entry.getValue(), exchange)) {
// We need to filter the content type with multi-part,
// as the multi-part stream is already consumed by AttachmentInInterceptor,
// it will cause some trouble when route this message to another CXF endpoint.
if ("Content-Type".compareToIgnoreCase(entry.getKey()) == 0
&& entry.getValue().get(0) != null
&& entry.getValue().get(0).startsWith("multipart/related")) {
// We need to keep the Content-Type if the data format is RAW message
DataFormat dataFormat = exchange.getProperty(CxfConstants.DATA_FORMAT_PROPERTY, DataFormat.class);
if (dataFormat.equals(DataFormat.RAW)) {
camelHeaders.put(entry.getKey(), getContentTypeString(entry.getValue()));
} else {
String contentType = replaceMultiPartContentType(entry.getValue().get(0));
LOG.trace("Find the multi-part Conent-Type, and replace it with {}", contentType);
camelHeaders.put(entry.getKey(), contentType);
}
} else {
LOG.trace("Populate header from CXF header={} value={}",
entry.getKey(), entry.getValue());
List<String> values = entry.getValue();
Object evalue;
if (values.size() > 1) {
if (exchange.getProperty(CxfConstants.CAMEL_CXF_PROTOCOL_HEADERS_MERGED, Boolean.FALSE, Boolean.class)) {
StringBuilder sb = new StringBuilder();
for (Iterator<String> it = values.iterator(); it.hasNext();) {
sb.append(it.next());
if (it.hasNext()) {
sb.append(',').append(' ');
}
}
evalue = sb.toString();
} else {
evalue = values;
}
} else if (values.size() == 1) {
evalue = values.get(0);
} else {
evalue = null;
}
if (evalue != null) {
camelHeaders.put(entry.getKey(), evalue);
}
}
}
}
}
// propagate SOAP/protocol header list
String key = Header.HEADER_LIST;
Object value = cxfMessage.get(key);
if (value != null) {
if (!headerFilterStrategy.applyFilterToExternalHeaders(key, value, exchange)) {
camelHeaders.put(key, value);
LOG.trace("Populate header from CXF header={} value={}", key, value);
} else {
((List<?>)value).clear();
}
}
// propagate the SOAPAction header
String soapAction = (String)camelHeaders.get(SoapBindingConstants.SOAP_ACTION);
// Remove SOAPAction from the protocol header, as it will not be overrided
if (ObjectHelper.isEmpty(soapAction) || "\"\"".equals(soapAction)) {
camelHeaders.remove(SoapBindingConstants.SOAP_ACTION);
}
soapAction = (String)cxfMessage.get(SoapBindingConstants.SOAP_ACTION);
if (soapAction != null) {
if (!headerFilterStrategy.applyFilterToExternalHeaders(SoapBindingConstants.SOAP_ACTION, soapAction, exchange)) {
camelHeaders.put(SoapBindingConstants.SOAP_ACTION, soapAction);
LOG.trace("Populate header from CXF header={} value={}", SoapBindingConstants.SOAP_ACTION, soapAction);
}
}
}
// replace the multi-part content-type
protected String replaceMultiPartContentType(String contentType) {
String result = "";
String[] parts = contentType.split(";");
for (String part : parts) {
part = part.trim();
if (part.startsWith("type=")) {
part = part.substring(5).trim();
if (part.charAt(0) == '\"') {
result = part.substring(1, part.length() - 1);
} else {
result = part.substring(5);
}
break;
}
}
return result;
}
protected String getContentTypeString(List<String> values) {
String result = "";
for (String value : values) {
if (result.length() == 0) {
result = value;
} else {
result = result + "; " + value;
}
}
return result;
}
@SuppressWarnings("unchecked")
protected void propagateHeadersFromCamelToCxf(Exchange camelExchange,
Map<String, Object> camelHeaders,
org.apache.cxf.message.Exchange cxfExchange,
Map<String, Object> cxfContext) {
// get cxf transport headers (if any) from camel exchange
// use a treemap to keep ordering and ignore key case
Map<String, List<String>> transportHeaders = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER);
if (camelExchange != null) {
Map<String, List<String>> h = CastUtils.cast((Map<?, ?>)camelExchange.getProperty(Message.PROTOCOL_HEADERS));
if (h != null) {
transportHeaders.putAll(h);
}
}
Map<String, List<String>> headers = CastUtils.cast((Map<?, ?>)camelHeaders.get(Message.PROTOCOL_HEADERS));
if (headers != null) {
transportHeaders.putAll(headers);
}
DataFormat dataFormat = camelExchange.getProperty(CxfConstants.DATA_FORMAT_PROPERTY, DataFormat.class);
for (Map.Entry<String, Object> entry : camelHeaders.entrySet()) {
// put response code in request context so it will be copied to CXF message's property
if (Message.RESPONSE_CODE.equals(entry.getKey()) || Exchange.HTTP_RESPONSE_CODE.equals(entry.getKey())) {
LOG.debug("Propagate to CXF header: {} value: {}", Message.RESPONSE_CODE, entry.getValue());
cxfContext.put(Message.RESPONSE_CODE, entry.getValue());
continue;
}
// We need to copy the content-type if the dataformat is RAW
if (Message.CONTENT_TYPE.equalsIgnoreCase(entry.getKey()) && dataFormat.equals(DataFormat.RAW)) {
LOG.debug("Propagate to CXF header: {} value: {}", Message.CONTENT_TYPE, entry.getValue());
cxfContext.put(Message.CONTENT_TYPE, entry.getValue().toString());
continue;
}
// need to filter the User-Agent ignore the case, as CXF just check the header with "User-Agent"
if (entry.getKey().equalsIgnoreCase("User-Agent")) {
List<String> listValue = new ArrayList<String>();
listValue.add(entry.getValue().toString());
transportHeaders.put("User-Agent", listValue);
}
// this header should be filtered, continue to the next header
if (headerFilterStrategy.applyFilterToCamelHeaders(entry.getKey(), entry.getValue(), camelExchange)) {
continue;
}
LOG.debug("Propagate to CXF header: {} value: {}", entry.getKey(), entry.getValue());
// put SOAP/protocol header list in exchange
if (Header.HEADER_LIST.equals(entry.getKey())) {
List<Header> headerList = (List<Header>)entry.getValue();
for (Header header : headerList) {
header.setDirection(Header.Direction.DIRECTION_OUT);
LOG.trace("Propagate SOAP/protocol header: {} : {}", header.getName(), header.getObject());
}
//cxfExchange.put(Header.HEADER_LIST, headerList);
cxfContext.put(entry.getKey(), headerList);
continue;
}
if (ObjectHelper.isNotEmpty(entry.getValue())) {
// things that are not filtered and not specifically copied will be put in transport headers
if (entry.getValue() instanceof List) {
transportHeaders.put(entry.getKey(), (List<String>)entry.getValue());
} else {
List<String> listValue = new ArrayList<String>();
listValue.add(entry.getValue().toString());
transportHeaders.put(entry.getKey(), listValue);
}
}
}
if (transportHeaders.size() > 0) {
cxfContext.put(Message.PROTOCOL_HEADERS, transportHeaders);
} else {
// no propagated transport headers does really mean no headers, not the ones
// from the previous request or response propagated with the invocation context
cxfContext.remove(Message.PROTOCOL_HEADERS);
}
cxfContext.put(SoapBindingConstants.SOAP_ACTION, camelHeaders.get(SoapBindingConstants.SOAP_ACTION));
}
protected static Object getContentFromCxf(Message message, DataFormat dataFormat, String encoding) {
Set<Class<?>> contentFormats = message.getContentFormats();
Object answer = null;
if (contentFormats != null) {
if (LOG.isTraceEnabled()) {
for (Class<?> contentFormat : contentFormats) {
LOG.trace("Content format={} value={}",
contentFormat, message.getContent(contentFormat));
}
}
if (dataFormat == DataFormat.POJO) {
answer = message.getContent(List.class);
if (answer == null) {
answer = message.getContent(Object.class);
if (answer != null) {
answer = new MessageContentsList(answer);
}
}
} else if (dataFormat == DataFormat.PAYLOAD) {
List<SoapHeader> headers = CastUtils.cast((List<?>)message.get(Header.HEADER_LIST));
Map<String, String> nsMap = new HashMap<String, String>();
answer = new CxfPayload<SoapHeader>(headers, getPayloadBodyElements(message, nsMap), nsMap);
} else if (dataFormat.dealias() == DataFormat.RAW) {
answer = message.getContent(InputStream.class);
if (answer == null) {
answer = message.getContent(Reader.class);
if (answer != null) {
if (encoding == null) {
encoding = "UTF-8";
}
LOG.trace("file encoding is = {}", encoding);
answer = new ReaderInputStream((Reader)answer, Charset.forName(encoding));
}
}
} else if (dataFormat.dealias() == DataFormat.CXF_MESSAGE
&& message.getContent(List.class) != null) {
// CAMEL-6404 added check point of message content
// The message content of list could be null if there is a fault message is received
answer = message.getContent(List.class).get(0);
}
LOG.trace("Extracted body from CXF message = {}", answer);
}
return answer;
}
protected static void addNamespace(Element element, Map<String, String> nsMap) {
for (Map.Entry<String, String> ns : nsMap.entrySet()) {
// We should not override the namespace setting of the element
if (XMLConstants.XMLNS_ATTRIBUTE.equals(ns.getKey())) {
if (ObjectHelper.isEmpty(element.getAttribute(XMLConstants.XMLNS_ATTRIBUTE))) {
element.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, ns.getKey(), ns.getValue());
}
} else if (StringUtils.isEmpty(ns.getKey())) {
if (ObjectHelper.isEmpty(element.getAttribute(XMLConstants.XMLNS_ATTRIBUTE))) {
element.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns", ns.getValue());
}
} else {
if (ObjectHelper.isEmpty(element.getAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":" + ns.getKey()))) {
element.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE + ":" + ns.getKey(), ns.getValue());
}
}
}
}
protected static List<Source> getPayloadBodyElements(Message message, Map<String, String> nsMap) {
// take the namespace attribute from soap envelop
Map<String, String> bodyNC = CastUtils.cast((Map<?, ?>)message.get("soap.body.ns.context"));
if (bodyNC != null) {
// if there is no Node and the addNamespaceContext option is enabled, this map is available
nsMap.putAll(bodyNC);
} else {
Document soapEnv = (Document) message.getContent(Node.class);
if (soapEnv != null) {
NamedNodeMap attrs = soapEnv.getFirstChild().getAttributes();
for (int i = 0; i < attrs.getLength(); i++) {
Node node = attrs.item(i);
if (!node.getNodeValue().equals(Soap11.SOAP_NAMESPACE)
&& !node.getNodeValue().equals(Soap12.SOAP_NAMESPACE)) {
nsMap.put(node.getLocalName(), node.getNodeValue());
}
}
}
}
MessageContentsList inObjects = MessageContentsList.getContentsList(message);
if (inObjects == null) {
return new ArrayList<Source>(0);
}
org.apache.cxf.message.Exchange exchange = message.getExchange();
BindingOperationInfo boi = exchange.getBindingOperationInfo();
OperationInfo op = boi.getOperationInfo();
if (boi.isUnwrapped()) {
op = boi.getWrappedOperation().getOperationInfo();
}
List<MessagePartInfo> partInfos = null;
boolean client = Boolean.TRUE.equals(message.get(Message.REQUESTOR_ROLE));
if (client) {
// it is a response
partInfos = op.getOutput().getMessageParts();
} else {
// it is a request
partInfos = op.getInput().getMessageParts();
}
List<Source> answer = new ArrayList<Source>();
for (MessagePartInfo partInfo : partInfos) {
if (!inObjects.hasValue(partInfo)) {
continue;
}
Object part = inObjects.get(partInfo);
if (part instanceof Holder) {
part = ((Holder<?>)part).value;
}
if (part instanceof Source) {
Element element = null;
if (part instanceof DOMSource) {
element = getFirstElement(((DOMSource)part).getNode());
}
if (element != null) {
addNamespace(element, nsMap);
answer.add(new DOMSource(element));
} else {
answer.add((Source)part);
}
if (LOG.isTraceEnabled()) {
LOG.trace("Extract body element {}",
element == null ? "null" : getXMLString(element));
}
} else if (part instanceof Element) {
addNamespace((Element)part, nsMap);
answer.add(new DOMSource((Element)part));
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Unhandled part type '{}'", part.getClass());
}
}
}
return answer;
}
private static String getXMLString(Element el) {
try {
return StaxUtils.toString(el);
} catch (Throwable t) {
//ignore
}
return "unknown content";
}
public static Object getBodyFromCamel(org.apache.camel.Message out,
DataFormat dataFormat) {
Object answer = null;
if (dataFormat == DataFormat.POJO) {
answer = out.getBody();
} else if (dataFormat == DataFormat.PAYLOAD) {
answer = out.getBody(CxfPayload.class);
} else if (dataFormat.dealias() == DataFormat.RAW) {
answer = out.getBody(InputStream.class);
} else if (dataFormat.dealias() == DataFormat.CXF_MESSAGE) {
answer = out.getBody();
}
return answer;
}
private static Element getFirstElement(Node node) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
return (Element)node;
}
return DOMUtils.getFirstElement(node);
}
public void copyJaxWsContext(org.apache.cxf.message.Exchange cxfExchange, Map<String, Object> context) {
if (cxfExchange.getOutMessage() != null) {
org.apache.cxf.message.Message outMessage = cxfExchange.getOutMessage();
for (Map.Entry<String, Object> entry : context.entrySet()) {
if (outMessage.get(entry.getKey()) == null) {
outMessage.put(entry.getKey(), entry.getValue());
}
}
}
}
public void extractJaxWsContext(org.apache.cxf.message.Exchange cxfExchange, Map<String, Object> context) {
org.apache.cxf.message.Message inMessage = cxfExchange.getInMessage();
for (Map.Entry<String, Object> entry : inMessage.entrySet()) {
if (entry.getKey().startsWith("javax.xml.ws")) {
context.put(entry.getKey(), entry.getValue());
}
}
}
//TODO replace this method with the cxf util's method when it becomes available
private static void changeToOneway(org.apache.cxf.message.Exchange cxfExchange) {
cxfExchange.setOneWay(true);
Object httpresp = cxfExchange.getInMessage().get("HTTP.RESPONSE");
if (httpresp != null) {
try {
Method m = findMethod(httpresp.getClass(), "setStatus", int.class);
if (m != null) {
m.invoke(httpresp, 202);
}
} catch (Exception e) {
LOG.warn("Unable to set the http ", e);
}
}
}
public static Method findMethod(Class<?> cls,
String name,
Class<?>... params) {
if (cls == null) {
return null;
}
for (Class<?> cs : cls.getInterfaces()) {
if (Modifier.isPublic(cs.getModifiers())) {
Method m = findMethod(cs, name, params);
if (m != null && Modifier.isPublic(m.getModifiers())) {
return m;
}
}
}
try {
Method m = cls.getDeclaredMethod(name, params);
if (m != null && Modifier.isPublic(m.getModifiers())) {
return m;
}
} catch (Exception e) {
//ignore
}
Method m = findMethod(cls.getSuperclass(), name, params);
if (m == null) {
try {
m = cls.getMethod(name, params);
} catch (Exception e) {
//ignore
}
}
return m;
}
}