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 */
017package org.apache.camel.impl;
018
019import org.apache.camel.AsyncCallback;
020import org.apache.camel.AsyncProcessor;
021import org.apache.camel.Endpoint;
022import org.apache.camel.Exchange;
023import org.apache.camel.ExchangePattern;
024import org.apache.camel.Producer;
025import org.apache.camel.util.ServiceHelper;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029import static org.apache.camel.processor.PipelineHelper.continueProcessing;
030
031/**
032 * {@link org.apache.camel.Processor} used to interceptor and detour the routing
033 * when using the {@link InterceptSendToEndpoint} functionality.
034 */
035public class InterceptSendToEndpointProcessor extends DefaultAsyncProducer {
036
037    private static final Logger LOG = LoggerFactory.getLogger(InterceptSendToEndpointProcessor.class);
038    private final InterceptSendToEndpoint endpoint;
039    private final Endpoint delegate;
040    private final Producer producer;
041    private final boolean skip;
042
043    public InterceptSendToEndpointProcessor(InterceptSendToEndpoint endpoint, Endpoint delegate, Producer producer, boolean skip) throws Exception {
044        super(delegate);
045        this.endpoint = endpoint;
046        this.delegate = delegate;
047        this.producer = producer;
048        this.skip = skip;
049    }
050
051    public Endpoint getEndpoint() {
052        return producer.getEndpoint();
053    }
054
055    public Exchange createExchange() {
056        return producer.createExchange();
057    }
058
059    public Exchange createExchange(ExchangePattern pattern) {
060        return producer.createExchange(pattern);
061    }
062
063    @Deprecated
064    public Exchange createExchange(Exchange exchange) {
065        return producer.createExchange(exchange);
066    }
067
068    @Override
069    public boolean process(Exchange exchange, AsyncCallback callback) {
070        // process the detour so we do the detour routing
071        if (LOG.isDebugEnabled()) {
072            LOG.debug("Sending to endpoint: {} is intercepted and detoured to: {} for exchange: {}", new Object[]{getEndpoint(), endpoint.getDetour(), exchange});
073        }
074        // add header with the real endpoint uri
075        exchange.getIn().setHeader(Exchange.INTERCEPTED_ENDPOINT, delegate.getEndpointUri());
076
077        if (endpoint.getDetour() != null) {
078            // detour the exchange using synchronous processing
079            try {
080                endpoint.getDetour().process(exchange);
081            } catch (Exception e) {
082                exchange.setException(e);
083            }
084        }
085
086        // Decide whether to continue or not; similar logic to the Pipeline
087        // check for error if so we should break out
088        if (!continueProcessing(exchange, "skip sending to original intended destination: " + getEndpoint(), LOG)) {
089            callback.done(true);
090            return true;
091        }
092
093        // determine if we should skip or not
094        boolean shouldSkip = skip;
095
096        // if then interceptor had a when predicate, then we should only skip if it matched
097        Boolean whenMatches = (Boolean) exchange.removeProperty(Exchange.INTERCEPT_SEND_TO_ENDPOINT_WHEN_MATCHED);
098        if (whenMatches != null) {
099            shouldSkip = skip && whenMatches;
100        }
101
102        if (!shouldSkip) {
103            if (exchange.hasOut()) {
104                // replace OUT with IN as detour changed something
105                exchange.setIn(exchange.getOut());
106                exchange.setOut(null);
107            }
108
109            // route to original destination leveraging the asynchronous routing engine if possible
110            if (producer instanceof AsyncProcessor) {
111                AsyncProcessor async = (AsyncProcessor) producer;
112                return async.process(exchange, callback);
113            } else {
114                try {
115                    producer.process(exchange);
116                } catch (Exception e) {
117                    exchange.setException(e);
118                }
119                callback.done(true);
120                return true;
121            }
122        } else {
123            if (LOG.isDebugEnabled()) {
124                LOG.debug("Stop() means skip sending exchange to original intended destination: {} for exchange: {}", getEndpoint(), exchange);
125            }
126            callback.done(true);
127            return true;
128        }
129    }
130
131    public boolean isSingleton() {
132        return producer.isSingleton();
133    }
134
135    public void start() throws Exception {
136        ServiceHelper.startService(endpoint.getDetour());
137        // here we also need to start the producer
138        ServiceHelper.startService(producer);
139    }
140
141    public void stop() throws Exception {
142        // do not stop detour as it should only be stopped when the interceptor stops
143        // we should stop the producer here
144        ServiceHelper.stopService(producer);
145    }
146
147}