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
038 */
039 @XmlRootElement(name = "interceptToEndpoint")
040 @XmlAccessorType(XmlAccessType.FIELD)
041 public class InterceptSendToEndpointDefinition extends OutputDefinition<InterceptSendToEndpointDefinition> {
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
053 private Boolean skipSendToOriginalEndpoint;
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 "interceptSendToEndpoint[" + uri + "]";
075 }
076
077 @Override
078 public boolean isAbstract() {
079 return true;
080 }
081
082 @Override
083 public Processor createProcessor(final RouteContext routeContext) throws Exception {
084 // create the detour
085 final Processor detour = this.createChildProcessor(routeContext, true);
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 if (endpoint instanceof InterceptSendToEndpoint) {
091 // endpoint already decorated
092 return endpoint;
093 } else if (getUri() == null || EndpointHelper.matchEndpoint(routeContext.getCamelContext(), uri, getUri())) {
094 // only proxy if the uri is matched decorate endpoint with our proxy
095 // should be false by default
096 boolean skip = isSkipSendToOriginalEndpoint();
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 InterceptSendToEndpointDefinition when(Predicate predicate) {
125 WhenDefinition when = new WhenDefinition(predicate);
126 addOutput(when);
127 return this;
128 }
129
130 /**
131 * Skip sending the {@link org.apache.camel.Exchange} to the original intended endpoint
132 *
133 * @return the builder
134 */
135 public InterceptSendToEndpointDefinition skipSendToOriginalEndpoint() {
136 setSkipSendToOriginalEndpoint(Boolean.TRUE);
137 return this;
138 }
139
140 /**
141 * This method is <b>only</b> for handling some post configuration
142 * that is needed since this is an interceptor, and we have to do
143 * a bit of magic logic to fixup to handle predicates
144 * with or without proceed/stop set as well.
145 */
146 public void afterPropertiesSet() {
147 // okay the intercept endpoint works a bit differently than the regular interceptors
148 // so we must fix the route definition yet again
149
150 if (getOutputs().size() == 0) {
151 // no outputs
152 return;
153 }
154
155 // if there is a when definition at first, then its a predicate for this interceptor
156 ProcessorDefinition<?> first = getOutputs().get(0);
157 if (first instanceof WhenDefinition && !(first instanceof WhenSkipSendToEndpointDefinition)) {
158 WhenDefinition when = (WhenDefinition) first;
159
160 // create a copy of when to use as replacement
161 WhenSkipSendToEndpointDefinition newWhen = new WhenSkipSendToEndpointDefinition();
162 newWhen.setExpression(when.getExpression());
163 newWhen.setId(when.getId());
164 newWhen.setInheritErrorHandler(when.isInheritErrorHandler());
165 newWhen.setParent(when.getParent());
166 newWhen.setOtherAttributes(when.getOtherAttributes());
167 newWhen.setNodeFactory(when.getNodeFactory());
168 newWhen.setDescription(when.getDescription());
169
170 // move this outputs to the when, expect the first one
171 // as the first one is the interceptor itself
172 for (int i = 1; i < outputs.size(); i++) {
173 ProcessorDefinition<?> out = outputs.get(i);
174 newWhen.addOutput(out);
175 }
176 // remove the moved from the original output, by just keeping the first one
177 clearOutput();
178 outputs.add(newWhen);
179 }
180 }
181
182 public Boolean getSkipSendToOriginalEndpoint() {
183 return skipSendToOriginalEndpoint;
184 }
185
186 public void setSkipSendToOriginalEndpoint(Boolean skipSendToOriginalEndpoint) {
187 this.skipSendToOriginalEndpoint = skipSendToOriginalEndpoint;
188 }
189
190 public boolean isSkipSendToOriginalEndpoint() {
191 return skipSendToOriginalEndpoint != null && skipSendToOriginalEndpoint;
192 }
193
194 public String getUri() {
195 return uri;
196 }
197
198 public void setUri(String uri) {
199 this.uri = uri;
200 }
201 }