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.impl;
018    
019    import java.util.Map;
020    
021    import org.apache.camel.CamelContext;
022    import org.apache.camel.Consumer;
023    import org.apache.camel.Endpoint;
024    import org.apache.camel.Exchange;
025    import org.apache.camel.ExchangePattern;
026    import org.apache.camel.PollingConsumer;
027    import org.apache.camel.Processor;
028    import org.apache.camel.Producer;
029    import org.apache.camel.util.ServiceHelper;
030    import org.apache.commons.logging.Log;
031    import org.apache.commons.logging.LogFactory;
032    
033    /**
034     * This is an endpoint when sending to it, is intercepted and is routed in a detour
035     *
036     * @version $Revision: 886693 $
037     */
038    public class InterceptSendToEndpoint implements Endpoint {
039    
040        private static final transient Log LOG = LogFactory.getLog(InterceptSendToEndpoint.class);
041    
042        private final Endpoint delegate;
043        private Producer producer;
044        private Processor detour;
045        private boolean skip;
046    
047        /**
048         * Intercepts sending to the given endpoint
049         *
050         * @param destination  the original endpoint
051         * @param skip <tt>true</tt> to skip sending after the detour to the original endpoint
052         */
053        public InterceptSendToEndpoint(final Endpoint destination, boolean skip) {
054            this.delegate = destination;
055            this.skip = skip;
056        }
057    
058        public void setDetour(Processor detour) {
059            this.detour = detour;
060        }
061    
062        public Endpoint getDelegate() {
063            return delegate;
064        }
065    
066        public String getEndpointUri() {
067            return delegate.getEndpointUri();
068        }
069    
070        public String getEndpointKey() {
071            return delegate.getEndpointKey();
072        }
073    
074        public Exchange createExchange() {
075            return delegate.createExchange();
076        }
077    
078        public Exchange createExchange(ExchangePattern pattern) {
079            return delegate.createExchange(pattern);
080        }
081    
082        public Exchange createExchange(Exchange exchange) {
083            return delegate.createExchange(exchange);
084        }
085    
086        public CamelContext getCamelContext() {
087            return delegate.getCamelContext();
088        }
089    
090        public Producer createProducer() throws Exception {
091            producer = delegate.createProducer();
092            return new Producer() {
093    
094                public Endpoint getEndpoint() {
095                    return producer.getEndpoint();
096                }
097    
098                public Exchange createExchange() {
099                    return producer.createExchange();
100                }
101    
102                public Exchange createExchange(ExchangePattern pattern) {
103                    return producer.createExchange(pattern);
104                }
105    
106                public Exchange createExchange(Exchange exchange) {
107                    return producer.createExchange(exchange);
108                }
109    
110                public void process(Exchange exchange) throws Exception {
111                    // process the detour so we do the detour routing
112                    if (LOG.isDebugEnabled()) {
113                        LOG.debug("Sending to endpoint: " + getEndpointUri() + " is intercepted and detoured to: " + detour + " for exchange: " + exchange);
114                    }
115                    // add header with the real endpoint uri
116                    exchange.getIn().setHeader(Exchange.INTERCEPTED_ENDPOINT, delegate.getEndpointUri());
117    
118                    try {
119                        detour.process(exchange);
120                    } catch (Exception e) {
121                        exchange.setException(e);
122                    }
123    
124                    // check for error if so we should break out
125                    boolean exceptionHandled = hasExceptionBeenHandledByErrorHandler(exchange);
126                    if (exchange.isFailed() || exchange.isRollbackOnly() || exceptionHandled) {
127                        // The Exchange.ERRORHANDLED_HANDLED property is only set if satisfactory handling was done
128                        // by the error handler. It's still an exception, the exchange still failed.
129                        if (LOG.isDebugEnabled()) {
130                            StringBuilder sb = new StringBuilder();
131                            sb.append("Message exchange has failed so skip sending to original intended destination: ").append(getEndpointUri());
132                            sb.append(" for Exchange: ").append(exchange);
133                            if (exchange.isRollbackOnly()) {
134                                sb.append(" Marked as rollback only.");
135                            }
136                            if (exchange.getException() != null) {
137                                sb.append(" Exception: ").append(exchange.getException());
138                            }
139                            if (exchange.hasOut() && exchange.getOut().isFault()) {
140                                sb.append(" Fault: ").append(exchange.getOut());
141                            }
142                            if (exceptionHandled) {
143                                sb.append(" Handled by the error handler.");
144                            }
145                            LOG.debug(sb.toString());
146                        }
147                        return;
148                    }
149    
150                    if (!skip) {
151                        if (exchange.hasOut()) {
152                            // replace OUT with IN as detour changed something
153                            exchange.setIn(exchange.getOut());
154                            exchange.setOut(null);
155                        }
156    
157                        // route to original destination
158                        producer.process(exchange);
159                    } else {
160                        if (LOG.isDebugEnabled()) {
161                            LOG.debug("Stop() means skip sending exchange to original intended destination: " + getEndpointUri() + " for exchange: " + exchange);
162                        }
163                    }
164                }
165    
166                public boolean isSingleton() {
167                    return producer.isSingleton();
168                }
169    
170                public void start() throws Exception {
171                    ServiceHelper.startService(detour);
172                }
173    
174                public void stop() throws Exception {
175                    ServiceHelper.stopService(detour);
176                }
177            };
178        }
179    
180        private static boolean hasExceptionBeenHandledByErrorHandler(Exchange nextExchange) {
181            return Boolean.TRUE.equals(nextExchange.getProperty(Exchange.ERRORHANDLER_HANDLED));
182        }
183    
184        public Consumer createConsumer(Processor processor) throws Exception {
185            return delegate.createConsumer(processor);
186        }
187    
188        public PollingConsumer createPollingConsumer() throws Exception {
189            return delegate.createPollingConsumer();
190        }
191    
192        public void configureProperties(Map<String, Object> options) {
193            delegate.configureProperties(options);
194        }
195    
196        public void setCamelContext(CamelContext context) {
197            delegate.setCamelContext(context);
198        }
199    
200        public boolean isLenientProperties() {
201            return delegate.isLenientProperties();
202        }
203    
204        public boolean isSingleton() {
205            return delegate.isSingleton();
206        }
207    
208        @Override
209        public String toString() {
210            return delegate.toString();
211        }
212    }