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.model;
018
019 import java.util.List;
020 import javax.xml.bind.annotation.XmlAccessType;
021 import javax.xml.bind.annotation.XmlAccessorType;
022 import javax.xml.bind.annotation.XmlAttribute;
023 import javax.xml.bind.annotation.XmlRootElement;
024
025 import org.apache.camel.Endpoint;
026 import org.apache.camel.Predicate;
027 import org.apache.camel.Processor;
028 import org.apache.camel.impl.InterceptSendToEndpoint;
029 import org.apache.camel.processor.InterceptEndpointProcessor;
030 import org.apache.camel.spi.EndpointStrategy;
031 import org.apache.camel.spi.RouteContext;
032 import org.apache.camel.util.EndpointHelper;
033
034 /**
035 * Represents an XML <interceptToEndpoint/> element
036 *
037 * @version $Revision: 896185 $
038 */
039 @XmlRootElement(name = "interceptToEndpoint")
040 @XmlAccessorType(XmlAccessType.FIELD)
041 public class InterceptSendToEndpointDefinition extends OutputDefinition<ProcessorDefinition> {
042
043 // TODO: Support lookup endpoint by ref (requires a bit more work)
044
045 // TODO: interceptSendToEndpoint needs to proxy the endpoints at very first
046 // so when other processors uses an endpoint its already proxied, see workaround in SendProcessor
047 // needed when we haven't proxied beforehand. This requires some work in the route builder in Camel
048 // to implement so that should be a part of a bigger rework/improvement in the future
049
050 @XmlAttribute(required = true)
051 private String uri;
052 @XmlAttribute(required = false)
053 private Boolean skipSendToOriginalEndpoint = Boolean.FALSE;
054
055 public InterceptSendToEndpointDefinition() {
056 }
057
058 public InterceptSendToEndpointDefinition(String uri) {
059 this.uri = uri;
060 }
061
062 @Override
063 public String toString() {
064 return "InterceptSendToEndpoint[" + uri + " -> " + getOutputs() + "]";
065 }
066
067 @Override
068 public String getShortName() {
069 return "interceptSendToEndpoint";
070 }
071
072 @Override
073 public String getLabel() {
074 return "interceptEndpoint";
075 }
076
077 @Override
078 public boolean isAbstract() {
079 return true;
080 }
081
082 @Override
083 public Processor createProcessor(RouteContext routeContext) throws Exception {
084 // create the detour
085 final Processor detour = routeContext.createProcessor(this);
086
087 // register endpoint callback so we can proxy the endpoint
088 routeContext.getCamelContext().addRegisterEndpointCallback(new EndpointStrategy() {
089 public Endpoint registerEndpoint(String uri, Endpoint endpoint) {
090
091 if (endpoint instanceof InterceptSendToEndpoint) {
092 // endpoint already decorated
093 return endpoint;
094 } else if (getUri() == null || EndpointHelper.matchEndpoint(uri, getUri())) {
095 // only proxy if the uri is matched decorate endpoint with our proxy
096 boolean skip = skipSendToOriginalEndpoint != null ? skipSendToOriginalEndpoint : false;
097 InterceptSendToEndpoint proxy = new InterceptSendToEndpoint(endpoint, skip);
098 proxy.setDetour(detour);
099 return proxy;
100 } else {
101 // no proxy so return regular endpoint
102 return endpoint;
103 }
104 }
105 });
106
107
108 // remove the original intercepted route from the outputs as we do not intercept as the regular interceptor
109 // instead we use the proxy endpoints producer do the triggering. That is we trigger when someone sends
110 // an exchange to the endpoint, see InterceptSendToEndpoint for details.
111 RouteDefinition route = routeContext.getRoute();
112 List<ProcessorDefinition> outputs = route.getOutputs();
113 outputs.remove(this);
114
115 return new InterceptEndpointProcessor(uri, detour);
116 }
117
118 /**
119 * Applies this interceptor only if the given predicate is true
120 *
121 * @param predicate the predicate
122 * @return the builder
123 */
124 public ChoiceDefinition when(Predicate predicate) {
125 return choice().when(predicate);
126 }
127
128 /**
129 * Skip sending the {@link org.apache.camel.Exchange} to the original intended endpoint
130 *
131 * @return the builder
132 */
133 public InterceptSendToEndpointDefinition skipSendToOriginalEndpoint() {
134 setSkipSendToOriginalEndpoint(Boolean.TRUE);
135 return this;
136 }
137
138 /**
139 * This method is <b>only</b> for handling some post configuration
140 * that is needed from the Spring DSL side as JAXB does not invoke the fluent
141 * builders, so we need to manually handle this afterwards, and since this is
142 * an interceptor it has to do a bit of magic logic to fixup to handle predicates
143 * with or without proceed/stop set as well.
144 */
145 public void afterPropertiesSet() {
146 // okay the intercept endpoint works a bit differently than the regular interceptors
147 // so we must fix the route definition yet again
148
149 if (getOutputs().size() == 0) {
150 // no outputs
151 return;
152 }
153
154 ProcessorDefinition first = getOutputs().get(0);
155 if (first instanceof WhenDefinition) {
156 WhenDefinition when = (WhenDefinition) first;
157 // move this outputs to the when, expect the first one
158 // as the first one is the interceptor itself
159 for (int i = 1; i < outputs.size(); i++) {
160 ProcessorDefinition out = outputs.get(i);
161 when.addOutput(out);
162 }
163 // remove the moved from the original output, by just keeping the first one
164 ProcessorDefinition keep = outputs.get(0);
165 clearOutput();
166 outputs.add(keep);
167 }
168 }
169
170 public Boolean getSkipSendToOriginalEndpoint() {
171 return skipSendToOriginalEndpoint;
172 }
173
174 public void setSkipSendToOriginalEndpoint(Boolean skipSendToOriginalEndpoint) {
175 this.skipSendToOriginalEndpoint = skipSendToOriginalEndpoint;
176 }
177
178 public String getUri() {
179 return uri;
180 }
181
182 public void setUri(String uri) {
183 this.uri = uri;
184 }
185 }