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.camel.processor;
018
019 import java.util.concurrent.Callable;
020 import java.util.concurrent.ExecutorService;
021
022 import org.apache.camel.Endpoint;
023 import org.apache.camel.Exchange;
024 import org.apache.camel.ExchangePattern;
025 import org.apache.camel.Expression;
026 import org.apache.camel.Processor;
027 import org.apache.camel.Producer;
028 import org.apache.camel.ProducerCallback;
029 import org.apache.camel.impl.DefaultExchange;
030 import org.apache.camel.util.ExchangeHelper;
031 import org.apache.camel.util.ObjectHelper;
032 import org.apache.camel.util.concurrent.ExecutorServiceHelper;
033
034 /**
035 * Processor for wire tapping exchanges to an endpoint destination.
036 *
037 * @version $Revision: 885197 $
038 */
039 public class WireTapProcessor extends SendProcessor {
040
041 private static final int DEFAULT_THREADPOOL_SIZE = 10;
042 private ExecutorService executorService;
043
044 // expression or processor used for populating a new exchange to send
045 // as opposed to traditional wiretap that sends a copy of the original exchange
046 private Expression newExchangeExpression;
047 private Processor newExchangeProcessor;
048
049 public WireTapProcessor(Endpoint destination) {
050 super(destination);
051 }
052
053 public WireTapProcessor(Endpoint destination, ExchangePattern pattern) {
054 super(destination, pattern);
055 }
056
057 @Override
058 protected void doStart() throws Exception {
059 super.doStart();
060 }
061
062 @Override
063 protected void doStop() throws Exception {
064 if (executorService != null) {
065 executorService.shutdown();
066 // must null it so we can restart
067 executorService = null;
068 }
069 super.doStop();
070 }
071
072 @Override
073 public String toString() {
074 return "WireTap[" + destination.getEndpointUri() + "]";
075 }
076
077 @Override
078 public String getTraceLabel() {
079 return "wireTap(" + destination.getEndpointUri() + ")";
080 }
081
082 public void process(Exchange exchange) throws Exception {
083 getProducerCache(exchange).doInProducer(destination, exchange, pattern, new ProducerCallback<Exchange>() {
084 public Exchange doInProducer(Producer producer, Exchange exchange, ExchangePattern pattern) throws Exception {
085 Exchange wireTapExchange = configureExchange(exchange, pattern);
086 procesWireTap(producer, wireTapExchange);
087 return wireTapExchange;
088 }
089 });
090 }
091
092 /**
093 * Wiretaps the exchange.
094 *
095 * @param exchange the exchange to wire tap
096 */
097 protected void procesWireTap(final Producer producer, final Exchange exchange) {
098 // use submit instead of execute to force it to use a new thread, execute might
099 // decide to use current thread, so we must submit a new task
100 // as we dont care for the response we dont hold the future object and wait for the result
101 getExecutorService().submit(new Callable<Exchange>() {
102 public Exchange call() throws Exception {
103 if (LOG.isDebugEnabled()) {
104 LOG.debug("Processing wiretap: " + exchange);
105 }
106 producer.process(exchange);
107 return exchange;
108 }
109 });
110 }
111
112 @Override
113 protected Exchange configureExchange(Exchange exchange, ExchangePattern pattern) {
114 Exchange answer;
115 if (newExchangeProcessor == null && newExchangeExpression == null) {
116 // use a copy of the original exchange
117 answer = configureCopyExchange(exchange);
118 } else {
119 // use a new exchange
120 answer = configureNewExchange(exchange);
121 }
122 // set property which endpoint we send to
123 answer.setProperty(Exchange.TO_ENDPOINT, destination.getEndpointUri());
124 return answer;
125 }
126
127 private Exchange configureCopyExchange(Exchange exchange) {
128 // must use a copy as we dont want it to cause side effects of the original exchange
129 Exchange copy = ExchangeHelper.createCorrelatedCopy(exchange, false);
130 // set MEP to InOnly as this wire tap is a fire and forget
131 copy.setPattern(ExchangePattern.InOnly);
132 return copy;
133 }
134
135 private Exchange configureNewExchange(Exchange exchange) {
136 Exchange answer = new DefaultExchange(exchange.getContext(), ExchangePattern.InOnly);
137 // use destination os origin of this new exchange
138 answer.setFromEndpoint(getDestination());
139
140 // prepare the exchange
141 if (newExchangeProcessor != null) {
142 try {
143 newExchangeProcessor.process(answer);
144 } catch (Exception e) {
145 throw ObjectHelper.wrapRuntimeCamelException(e);
146 }
147 } else {
148 Object body = newExchangeExpression.evaluate(answer, Object.class);
149 if (body != null) {
150 answer.getIn().setBody(body);
151 }
152 }
153
154 return answer;
155 }
156
157 public ExecutorService getExecutorService() {
158 if (executorService == null || executorService.isShutdown()) {
159 executorService = createExecutorService();
160 }
161 return executorService;
162 }
163
164 private ExecutorService createExecutorService() {
165 return ExecutorServiceHelper.newScheduledThreadPool(DEFAULT_THREADPOOL_SIZE, this.toString(), true);
166 }
167
168 public void setExecutorService(ExecutorService executorService) {
169 this.executorService = executorService;
170 }
171
172 public Processor getNewExchangeProcessor() {
173 return newExchangeProcessor;
174 }
175
176 public void setNewExchangeProcessor(Processor newExchangeProcessor) {
177 this.newExchangeProcessor = newExchangeProcessor;
178 }
179
180 public Expression getNewExchangeExpression() {
181 return newExchangeExpression;
182 }
183
184 public void setNewExchangeExpression(Expression newExchangeExpression) {
185 this.newExchangeExpression = newExchangeExpression;
186 }
187 }