/**
* 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.transport;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.camel.CamelContext;
import org.apache.camel.Consumer;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.cxf.CxfConstants;
import org.apache.camel.component.cxf.CxfSoapBinding;
import org.apache.camel.component.cxf.util.CxfHeaderHelper;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.spi.HeaderFilterStrategy;
import org.apache.cxf.Bus;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.configuration.Configurable;
import org.apache.cxf.configuration.Configurer;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageImpl;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.transport.AbstractConduit;
import org.apache.cxf.transport.AbstractDestination;
import org.apache.cxf.transport.Conduit;
import org.apache.cxf.transport.ConduitInitiator;
import org.apache.cxf.transport.MessageObserver;
import org.apache.cxf.ws.addressing.EndpointReferenceType;
import org.apache.cxf.wsdl.EndpointReferenceUtils;
/**
* @version $Revision: 680645 $
*/
public class CamelDestination extends AbstractDestination implements Configurable {
protected static final String BASE_BEAN_NAME_SUFFIX = ".camel-destination";
private static final Logger LOG = LogUtils.getL7dLogger(CamelDestination.class);
final ConduitInitiator conduitInitiator;
CamelContext camelContext;
Consumer consumer;
String camelDestinationUri;
private ProducerTemplate<Exchange> camelTemplate;
private Endpoint distinationEndpoint;
private HeaderFilterStrategy headerFilterStrategy;
public CamelDestination(CamelContext camelContext, Bus bus, ConduitInitiator ci, EndpointInfo info) throws IOException {
this(camelContext, bus, ci, info, null);
}
public CamelDestination(CamelContext camelContext, Bus bus, ConduitInitiator ci, EndpointInfo info,
HeaderFilterStrategy headerFilterStrategy) throws IOException {
super(bus, getTargetReference(info, bus), info);
this.camelContext = camelContext;
conduitInitiator = ci;
camelDestinationUri = endpointInfo.getAddress().substring(CxfConstants.CAMEL_TRANSPORT_PREFIX.length());
if (camelDestinationUri.startsWith("//")) {
camelDestinationUri = camelDestinationUri.substring(2);
}
initConfig();
this.headerFilterStrategy = headerFilterStrategy;
}
protected Logger getLogger() {
return LOG;
}
/**
* @param inMessage the incoming message
* @return the inbuilt backchannel
*/
protected Conduit getInbuiltBackChannel(Message inMessage) {
//we can pass the message back by looking up the camelExchange from inMessage
return new BackChannelConduit(inMessage);
}
public void activate() {
getLogger().log(Level.FINE, "CamelDestination activate().... ");
try {
getLogger().log(Level.FINE, "establishing Camel connection");
distinationEndpoint = camelContext.getEndpoint(camelDestinationUri);
consumer = distinationEndpoint.createConsumer(new ConsumerProcessor());
consumer.start();
} catch (Exception ex) {
// TODO: Is it okay just to log severe errors such as this?
getLogger().log(Level.SEVERE, "Camel connect failed with Exception : ", ex);
}
}
public void deactivate() {
try {
consumer.stop();
} catch (Exception e) {
// TODO: Is it okay just to log severe errors such as this?
getLogger().log(Level.SEVERE, "Camel stop failed with Exception : ", e);
}
}
public void shutdown() {
getLogger().log(Level.FINE, "CamelDestination shutdown()");
this.deactivate();
}
public ProducerTemplate<Exchange> getCamelTemplate() {
if (camelTemplate == null) {
CamelContext ctx = camelContext != null ? camelContext : new DefaultCamelContext();
camelTemplate = ctx.createProducerTemplate();
}
return camelTemplate;
}
public void setCamelTemplate(ProducerTemplate<Exchange> template) {
camelTemplate = template;
}
public void setCamelContext(CamelContext context) {
camelContext = context;
}
public CamelContext getCamelContext() {
return camelContext;
}
protected void incoming(org.apache.camel.Exchange camelExchange) {
getLogger().log(Level.FINE, "server received request: ", camelExchange);
org.apache.cxf.message.Message inMessage =
CxfSoapBinding.getCxfInMessage(headerFilterStrategy, camelExchange, false);
inMessage.put(CxfConstants.CAMEL_EXCHANGE, camelExchange);
((MessageImpl)inMessage).setDestination(this);
// Handling the incoming message
// The response message will be send back by the outgoingchain
incomingObserver.onMessage(inMessage);
}
public String getBeanName() {
if (endpointInfo == null || endpointInfo.getName() == null) {
return "default" + BASE_BEAN_NAME_SUFFIX;
}
return endpointInfo.getName().toString() + BASE_BEAN_NAME_SUFFIX;
}
private void initConfig() {
//we could configure the camel context here
if (bus != null) {
Configurer configurer = bus.getExtension(Configurer.class);
if (null != configurer) {
configurer.configureBean(this);
}
}
}
protected class ConsumerProcessor implements Processor {
public void process(Exchange exchange) {
try {
incoming(exchange);
} catch (Throwable ex) {
getLogger().log(Level.WARNING, "Failed to process incoming message : ", ex);
}
}
}
// this should deal with the cxf message
protected class BackChannelConduit extends AbstractConduit {
protected Message inMessage;
Exchange camelExchange;
org.apache.cxf.message.Exchange cxfExchange;
BackChannelConduit(Message message) {
super(EndpointReferenceUtils.getAnonymousEndpointReference());
inMessage = message;
cxfExchange = inMessage.getExchange();
camelExchange = cxfExchange.get(Exchange.class);
}
/**
* Register a message observer for incoming messages.
*
* @param observer the observer to notify on receipt of incoming
*/
public void setMessageObserver(MessageObserver observer) {
// shouldn't be called for a back channel conduit
}
/**
* Send an outbound message, assumed to contain all the name-value
* mappings of the corresponding input message (if any).
*
* @param message the message to be sent.
*/
public void prepare(Message message) throws IOException {
message.put(CxfConstants.CAMEL_EXCHANGE, inMessage.get(CxfConstants.CAMEL_EXCHANGE));
message.setContent(OutputStream.class, new CamelOutputStream(message));
}
protected Logger getLogger() {
return LOG;
}
}
/**
* Mark message as a partial message.
*
* @param partialResponse the partial response message
* @param decoupledTarget the decoupled target
* @return <tt>true</tt> if partial responses is supported
*/
protected boolean markPartialResponse(Message partialResponse,
EndpointReferenceType decoupledTarget) {
return true;
}
/**
* @return the associated conduit initiator
*/
protected ConduitInitiator getConduitInitiator() {
return conduitInitiator;
}
private class CamelOutputStream extends CachedOutputStream {
private Message outMessage;
public CamelOutputStream(Message m) {
super();
outMessage = m;
}
// Prepare the message and get the send out message
private void commitOutputMessage() throws IOException {
Exchange camelExchange = (Exchange)outMessage.get(CxfConstants.CAMEL_EXCHANGE);
CxfHeaderHelper.propagateCxfToCamel(headerFilterStrategy, outMessage, camelExchange.getOut().getHeaders());
CachedOutputStream outputStream = (CachedOutputStream)outMessage.getContent(OutputStream.class);
camelExchange.getOut().setBody(outputStream.getBytes());
getLogger().log(Level.FINE, "send the response message: " + outputStream);
}
@Override
protected void doFlush() throws IOException {
// Do nothing here
}
@Override
protected void doClose() throws IOException {
commitOutputMessage();
}
@Override
protected void onWrite() throws IOException {
// Do nothing here
}
}
}