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.ArrayList;
020 import java.util.List;
021 import javax.xml.bind.annotation.XmlAccessType;
022 import javax.xml.bind.annotation.XmlAccessorType;
023 import javax.xml.bind.annotation.XmlRootElement;
024 import javax.xml.bind.annotation.XmlTransient;
025
026 import org.apache.camel.Predicate;
027 import org.apache.camel.Processor;
028 import org.apache.camel.builder.PredicateBuilder;
029 import org.apache.camel.processor.Interceptor;
030 import org.apache.camel.spi.RouteContext;
031
032
033 /**
034 * Represents an XML <intercept/> element
035 *
036 * @version $Revision: 751221 $
037 */
038 @XmlRootElement(name = "intercept")
039 @XmlAccessorType(XmlAccessType.FIELD)
040 public class InterceptDefinition extends OutputDefinition<ProcessorDefinition> {
041
042 @XmlTransient
043 private ProceedDefinition proceed = new ProceedDefinition();
044 @XmlTransient
045 private Boolean stopIntercept = Boolean.FALSE;
046 @XmlTransient
047 private Boolean usePredicate = Boolean.FALSE;
048
049 @Override
050 public String toString() {
051 return "Intercept[" + getOutputs() + "]";
052 }
053
054 @Override
055 public String getShortName() {
056 return "intercept";
057 }
058
059 @Override
060 public String getLabel() {
061 return "intercept";
062 }
063
064 @Override
065 public Processor createProcessor(RouteContext routeContext) throws Exception {
066 Interceptor interceptor = new Interceptor();
067 routeContext.intercept(interceptor);
068
069 final Processor interceptRoute = createOutputsProcessor(routeContext);
070 interceptor.setInterceptorLogic(interceptRoute);
071
072 return interceptor;
073 }
074
075 /**
076 * Applies this interceptor only if the given predicate is true
077 *
078 * @param predicate the predicate
079 * @return the builder
080 */
081 public ChoiceDefinition when(Predicate predicate) {
082 usePredicate = Boolean.TRUE;
083 ChoiceDefinition choice = choice().when(PredicateBuilder.not(predicate));
084 choice.addOutput(proceed);
085 return choice.otherwise();
086 }
087
088 public ProceedDefinition getProceed() {
089 return proceed;
090 }
091
092 public void stopIntercept() {
093 setStopIntercept(Boolean.TRUE);
094 }
095
096 /**
097 * This method is <b>only</b> for handling some post configuration
098 * that is needed from the Spring DSL side as JAXB does not invoke the fluent
099 * builders, so we need to manually handle this afterwards, and since this is
100 * an interceptor it has to do a bit of magic logic to fixup to handle predicates
101 * with or without proceed/stop set as well.
102 */
103 public void afterPropertiesSet() {
104 List<ProcessorDefinition> list = new ArrayList<ProcessorDefinition>();
105 for (ProcessorDefinition out : outputs) {
106 if (out instanceof WhenDefinition) {
107 // JAXB does not invoke the when() fluent builder so we need to wrap the when in
108 // a choice with the proceed as the when for the Java DSL does
109 WhenDefinition when = (WhenDefinition) out;
110 usePredicate = Boolean.TRUE;
111 ChoiceDefinition choice = new ChoiceDefinition();
112 choice.when(PredicateBuilder.not(when.getExpression()));
113 choice.addOutput(proceed);
114 list.add(choice);
115
116 ChoiceDefinition otherwise = choice.otherwise();
117 // add the children to the otherwise
118 for (ProcessorDefinition child : when.getOutputs()) {
119 if (child instanceof StopDefinition) {
120 // notify we should stop
121 stopIntercept();
122 } else {
123 otherwise.addOutput(child);
124 }
125 }
126 } else if (out instanceof StopDefinition) {
127 // notify we shuld stop
128 stopIntercept();
129 } else {
130 list.add(out);
131 }
132 }
133
134 // replace old output with this redone output list
135 outputs.clear();
136 for (ProcessorDefinition out : list) {
137 addOutput(out);
138 }
139 }
140
141 public InterceptDefinition createProxy() {
142 InterceptDefinition answer = new InterceptDefinition();
143 answer.getOutputs().addAll(this.getOutputs());
144
145 answer.setStopIntercept(getStopIntercept());
146
147 // hack: now we need to replace the proceed of the proxy with its own
148 // a bit ugly, operating based on the assumption that the proceed is
149 // in its outputs (if proceed() was called) and/or in the
150 // outputs of the otherwise or last when clause for the predicated version.
151 if (answer.getOutputs().size() > 0) {
152 // this is for the predicate version or if a choice() is present
153 ChoiceDefinition choice = null;
154 for (ProcessorDefinition processor : answer.getOutputs()) {
155 if (processor instanceof ChoiceDefinition) {
156 // special cases for predicates (choices)
157 choice = (ChoiceDefinition) processor;
158
159 // for the predicated version we add the proceed() to otherwise()
160 // before knowing if stop() will follow, so let's make a small adjustment
161 if (usePredicate && getStopIntercept()) {
162 WhenDefinition when = choice.getWhenClauses().get(0);
163 when.getOutputs().remove(this.getProceed());
164 }
165
166 // add proceed to the when clause
167 addProceedProxy(this.getProceed(), answer.getProceed(),
168 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate && !getStopIntercept());
169
170 // force adding a proceed at the end (otherwise) if its not a stop type
171 addProceedProxy(this.getProceed(), answer.getProceed(), choice.getOtherwise(), !getStopIntercept());
172
173 if (getStopIntercept()) {
174 // must add proceed to when clause if stop is explictiy declared, otherwise when the
175 // predicate test fails then there is no proceed
176 // See example: InterceptorSimpleRouteTest (City Paris is never proceeded)
177 addProceedProxy(this.getProceed(), answer.getProceed(),
178 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate);
179 }
180
181 break;
182 }
183 }
184 if (choice == null) {
185 // force adding a proceed at the end if its not a stop type
186 addProceedProxy(this.getProceed(), answer.getProceed(), answer, !getStopIntercept());
187 }
188 }
189
190 return answer;
191 }
192
193 private void addProceedProxy(ProceedDefinition orig, ProceedDefinition proxy, ProcessorDefinition<?> processor, boolean force) {
194 int index = processor.getOutputs().indexOf(orig);
195 if (index >= 0) {
196 processor.addOutput(proxy);
197 // replace original proceed with proxy
198 List<ProcessorDefinition> outs = processor.getOutputs();
199 outs.remove(proxy);
200 outs.set(index, proxy);
201 } else if (force) {
202 processor.addOutput(proxy);
203 }
204 }
205
206 public void setStopIntercept(Boolean stop) {
207 this.stopIntercept = stop;
208 }
209
210 public Boolean getStopIntercept() {
211 return stopIntercept;
212 }
213
214 }