001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.camel;
018
019
020 import javax.jbi.messaging.ExchangeStatus;
021 import javax.jbi.messaging.Fault;
022 import javax.jbi.messaging.InOnly;
023 import javax.jbi.messaging.MessageExchange;
024 import javax.jbi.messaging.MessagingException;
025 import javax.jbi.messaging.RobustInOnly;
026 import javax.xml.namespace.QName;
027 import javax.xml.transform.Source;
028
029 import org.apache.camel.Endpoint;
030 import org.apache.camel.Exchange;
031 import org.apache.camel.Processor;
032 import org.apache.servicemix.JbiConstants;
033 import org.apache.servicemix.common.ServiceUnit;
034 import org.apache.servicemix.common.endpoints.ProviderEndpoint;
035 import org.apache.servicemix.jbi.FaultException;
036
037 /**
038 * A JBI endpoint which when invoked will delegate to a Camel endpoint
039 *
040 * @version $Revision: 426415 $
041 */
042 public class CamelProviderEndpoint extends ProviderEndpoint {
043
044 public static final QName SERVICE_NAME = new QName("http://activemq.apache.org/camel/schema/jbi", "provider");
045
046 private JbiBinding binding;
047
048 private Processor camelProcessor;
049
050 public CamelProviderEndpoint(ServiceUnit serviceUnit, QName service, String endpoint, JbiBinding binding, Processor camelProcessor) {
051 super(serviceUnit, service, endpoint);
052 this.camelProcessor = camelProcessor;
053 this.binding = binding;
054 }
055
056 public CamelProviderEndpoint(ServiceUnit serviceUnit, Endpoint camelEndpoint, JbiBinding binding, Processor camelProcessor) {
057 this(serviceUnit, SERVICE_NAME, camelEndpoint.getEndpointUri(), binding, camelProcessor);
058 }
059
060 @Override
061 public void process(MessageExchange exchange) throws Exception {
062 // The component acts as a provider, this means that another component has requested our service
063 // As this exchange is active, this is either an in or a fault (out are sent by this component)
064
065 if (exchange.getRole() == MessageExchange.Role.PROVIDER) {
066 // Exchange is finished
067 if (exchange.getStatus() == ExchangeStatus.DONE) {
068 return;
069 // Exchange has been aborted with an exception
070 } else if (exchange.getStatus() == ExchangeStatus.ERROR) {
071 return;
072 // Exchange is active
073 } else {
074 handleActiveProviderExchange(exchange);
075
076 }
077 // Unsupported role: this should never happen has we never create exchanges
078 } else {
079 throw new IllegalStateException("Unsupported role: " + exchange.getRole());
080 }
081 }
082
083
084 protected void handleActiveProviderExchange(MessageExchange exchange) throws Exception {
085 // Fault message
086 if (exchange.getFault() != null) {
087 done(exchange);
088 // In message
089 } else if (exchange.getMessage("in") != null) {
090 if (logger.isDebugEnabled()) {
091 logger.debug("Received exchange: " + exchange);
092 }
093 Exchange camelExchange = binding.createExchange(exchange);
094 camelProcessor.process(camelExchange);
095 if (camelExchange.isFailed()) {
096 handleFailure(exchange, camelExchange);
097 } else {
098 handleSuccess(exchange, camelExchange);
099 }
100 // This is not compliant with the default MEPs
101 } else {
102 throw new IllegalStateException("Provider exchange is ACTIVE, but no in or fault is provided");
103 }
104 }
105
106 /*
107 * Handle successful camel invocation
108 */
109 private void handleSuccess(MessageExchange exchange, Exchange camelExchange) throws MessagingException {
110 binding.copyFromCamelToJbi(camelExchange, exchange);
111 if (exchange instanceof InOnly || exchange instanceof RobustInOnly) {
112 done(exchange);
113 } else {
114 doSend(exchange);
115 }
116 }
117
118 /*
119 * Handle failure during camel route invocation
120 */
121 private void handleFailure(MessageExchange exchange, Exchange camelExchange) throws MessagingException {
122 if (camelExchange.getFault(false) == null || camelExchange.getFault(false).getBody() == null) {
123 fail(exchange, binding.extractException(camelExchange));
124 } else {
125 Fault fault = exchange.createFault();
126 fault.setContent(camelExchange.getFault().getBody(Source.class));
127 if (isFaultCapable(exchange)) {
128 exchange.setFault(fault);
129 doSend(exchange);
130 } else {
131 // MessageExchange is not capable of conveying faults -- sending the information as an error instead
132 fail(exchange, new FaultException("Fault occured for " + exchange.getPattern() + " exchange", exchange, fault));
133 }
134 }
135 }
136
137 /*
138 * Check if the exchange is capable of conveying fault messages
139 */
140 private boolean isFaultCapable(MessageExchange exchange) {
141 return !(exchange instanceof InOnly);
142 }
143
144 /*
145 * Send back the response, taking care to use sendSync when necessary
146 */
147 private void doSend(MessageExchange exchange) throws MessagingException {
148 boolean txSync = exchange.isTransacted() && Boolean.TRUE.equals(exchange.getProperty(JbiConstants.SEND_SYNC));
149 if (txSync && ExchangeStatus.ACTIVE.equals(exchange.getStatus())) {
150 sendSync(exchange);
151 } else {
152 send(exchange);
153 }
154 }
155 }