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 java.util.Map; 020 021import org.apache.camel.AsyncCallback; 022import org.apache.camel.AsyncProcessor; 023import org.apache.camel.CamelContext; 024import org.apache.camel.Consumer; 025import org.apache.camel.Endpoint; 026import org.apache.camel.EndpointConfiguration; 027import org.apache.camel.Exchange; 028import org.apache.camel.ExchangePattern; 029import org.apache.camel.PollingConsumer; 030import org.apache.camel.Processor; 031import org.apache.camel.Producer; 032import org.apache.camel.ShutdownableService; 033import org.apache.camel.util.ServiceHelper; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037import static org.apache.camel.processor.PipelineHelper.continueProcessing; 038 039/** 040 * This is an endpoint when sending to it, is intercepted and is routed in a detour 041 * 042 * @version 043 */ 044public class InterceptSendToEndpoint implements Endpoint, ShutdownableService { 045 046 private static final Logger LOG = LoggerFactory.getLogger(InterceptSendToEndpoint.class); 047 048 private final Endpoint delegate; 049 private Producer producer; 050 private Processor detour; 051 private boolean skip; 052 053 /** 054 * Intercepts sending to the given endpoint 055 * 056 * @param destination the original endpoint 057 * @param skip <tt>true</tt> to skip sending after the detour to the original endpoint 058 */ 059 public InterceptSendToEndpoint(final Endpoint destination, boolean skip) { 060 this.delegate = destination; 061 this.skip = skip; 062 } 063 064 public void setDetour(Processor detour) { 065 this.detour = detour; 066 } 067 068 public Endpoint getDelegate() { 069 return delegate; 070 } 071 072 public String getEndpointUri() { 073 return delegate.getEndpointUri(); 074 } 075 076 public EndpointConfiguration getEndpointConfiguration() { 077 return delegate.getEndpointConfiguration(); 078 } 079 080 public String getEndpointKey() { 081 return delegate.getEndpointKey(); 082 } 083 084 public Exchange createExchange() { 085 return delegate.createExchange(); 086 } 087 088 public Exchange createExchange(ExchangePattern pattern) { 089 return delegate.createExchange(pattern); 090 } 091 092 @Deprecated 093 public Exchange createExchange(Exchange exchange) { 094 return delegate.createExchange(exchange); 095 } 096 097 public CamelContext getCamelContext() { 098 return delegate.getCamelContext(); 099 } 100 101 public Producer createProducer() throws Exception { 102 producer = delegate.createProducer(); 103 return new DefaultAsyncProducer(delegate) { 104 105 public Endpoint getEndpoint() { 106 return producer.getEndpoint(); 107 } 108 109 public Exchange createExchange() { 110 return producer.createExchange(); 111 } 112 113 public Exchange createExchange(ExchangePattern pattern) { 114 return producer.createExchange(pattern); 115 } 116 117 @Deprecated 118 public Exchange createExchange(Exchange exchange) { 119 return producer.createExchange(exchange); 120 } 121 122 @Override 123 public boolean process(Exchange exchange, AsyncCallback callback) { 124 // process the detour so we do the detour routing 125 if (LOG.isDebugEnabled()) { 126 LOG.debug("Sending to endpoint: {} is intercepted and detoured to: {} for exchange: {}", new Object[]{getEndpoint(), detour, exchange}); 127 } 128 // add header with the real endpoint uri 129 exchange.getIn().setHeader(Exchange.INTERCEPTED_ENDPOINT, delegate.getEndpointUri()); 130 131 // detour the exchange using synchronous processing 132 try { 133 detour.process(exchange); 134 } catch (Exception e) { 135 exchange.setException(e); 136 } 137 138 // Decide whether to continue or not; similar logic to the Pipeline 139 // check for error if so we should break out 140 if (!continueProcessing(exchange, "skip sending to original intended destination: " + getEndpoint(), LOG)) { 141 callback.done(true); 142 return true; 143 } 144 145 // determine if we should skip or not 146 boolean shouldSkip = skip; 147 148 // if then interceptor had a when predicate, then we should only skip if it matched 149 Boolean whenMatches = (Boolean) exchange.removeProperty(Exchange.INTERCEPT_SEND_TO_ENDPOINT_WHEN_MATCHED); 150 if (whenMatches != null) { 151 shouldSkip = skip && whenMatches; 152 } 153 154 if (!shouldSkip) { 155 if (exchange.hasOut()) { 156 // replace OUT with IN as detour changed something 157 exchange.setIn(exchange.getOut()); 158 exchange.setOut(null); 159 } 160 161 // route to original destination leveraging the asynchronous routing engine if possible 162 if (producer instanceof AsyncProcessor) { 163 AsyncProcessor async = (AsyncProcessor) producer; 164 return async.process(exchange, callback); 165 } else { 166 try { 167 producer.process(exchange); 168 } catch (Exception e) { 169 exchange.setException(e); 170 } 171 callback.done(true); 172 return true; 173 } 174 } else { 175 if (LOG.isDebugEnabled()) { 176 LOG.debug("Stop() means skip sending exchange to original intended destination: {} for exchange: {}", getEndpoint(), exchange); 177 } 178 callback.done(true); 179 return true; 180 } 181 } 182 183 public boolean isSingleton() { 184 return producer.isSingleton(); 185 } 186 187 public void start() throws Exception { 188 ServiceHelper.startService(detour); 189 // here we also need to start the producer 190 ServiceHelper.startService(producer); 191 } 192 193 public void stop() throws Exception { 194 // do not stop detour as it should only be stopped when the interceptor stops 195 // we should stop the producer here 196 ServiceHelper.stopService(producer); 197 } 198 }; 199 } 200 201 public Consumer createConsumer(Processor processor) throws Exception { 202 return delegate.createConsumer(processor); 203 } 204 205 public PollingConsumer createPollingConsumer() throws Exception { 206 return delegate.createPollingConsumer(); 207 } 208 209 public void configureProperties(Map<String, Object> options) { 210 delegate.configureProperties(options); 211 } 212 213 public void setCamelContext(CamelContext context) { 214 delegate.setCamelContext(context); 215 } 216 217 public boolean isLenientProperties() { 218 return delegate.isLenientProperties(); 219 } 220 221 public boolean isSingleton() { 222 return delegate.isSingleton(); 223 } 224 225 public void start() throws Exception { 226 ServiceHelper.startServices(detour, delegate); 227 } 228 229 public void stop() throws Exception { 230 ServiceHelper.stopServices(delegate, detour); 231 } 232 233 @Override 234 public void shutdown() throws Exception { 235 ServiceHelper.stopAndShutdownServices(delegate, detour); 236 } 237 238 @Override 239 public String toString() { 240 return delegate.toString(); 241 } 242}