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.Collection;
020 import java.util.Collections;
021 import java.util.List;
022
023 import javax.xml.bind.annotation.XmlAccessType;
024 import javax.xml.bind.annotation.XmlAccessorType;
025 import javax.xml.bind.annotation.XmlElement;
026 import javax.xml.bind.annotation.XmlRootElement;
027 import javax.xml.bind.annotation.XmlTransient;
028
029 import org.apache.camel.Intercept;
030 import org.apache.camel.Predicate;
031 import org.apache.camel.Processor;
032 import org.apache.camel.builder.PredicateBuilder;
033 import org.apache.camel.processor.Interceptor;
034 import org.apache.camel.spi.RouteContext;
035
036
037 /**
038 * Represents an XML <intercept/> element
039 *
040 * @version $Revision: 699876 $
041 */
042 @XmlRootElement(name = "intercept")
043 @XmlAccessorType(XmlAccessType.FIELD)
044 public class InterceptType extends OutputType<ProcessorType> {
045
046 @XmlTransient
047 private ProceedType proceed = new ProceedType();
048 @XmlTransient
049 private Boolean stopIntercept = Boolean.FALSE;
050 @XmlTransient
051 private Boolean usePredicate = Boolean.FALSE;
052
053 @Override
054 public String toString() {
055 return "Intercept[" + getOutputs() + "]";
056 }
057
058 @Override
059 public String getShortName() {
060 return "intercept";
061 }
062
063 @Override
064 public String getLabel() {
065 return "intercept";
066 }
067
068 @Override
069 public Processor createProcessor(RouteContext routeContext) throws Exception {
070 Interceptor interceptor = new Interceptor();
071 routeContext.intercept(interceptor);
072
073 final Processor interceptRoute = createOutputsProcessor(routeContext);
074 interceptor.setInterceptorLogic(interceptRoute);
075
076 return interceptor;
077 }
078
079 /**
080 * Applies this interceptor only if the given predicate is true
081 */
082 public ChoiceType when(Predicate predicate) {
083 usePredicate = Boolean.TRUE;
084 ChoiceType choice = choice().when(PredicateBuilder.not(predicate));
085 choice.addOutput(proceed);
086 return choice.otherwise();
087 }
088
089 public ProceedType getProceed() {
090 return proceed;
091 }
092
093 public void stopIntercept() {
094 setStopIntercept(Boolean.TRUE);
095 }
096
097 @XmlElement(name = "stop", required = false)
098 public void setStop(String elementValue /* not used */) {
099 stopIntercept();
100 }
101
102 public InterceptType createProxy() {
103 InterceptType answer = new InterceptType();
104 answer.getOutputs().addAll(this.getOutputs());
105
106 answer.setStopIntercept(getStopIntercept());
107
108 // hack: now we need to replace the proceed of the proxy with its own
109 // a bit ugly, operating based on the assumption that the proceed is
110 // in its outputs (if proceed() was called) and/or in the
111 // outputs of the otherwise or last when clause for the predicated version.
112 if (answer.getOutputs().size() > 0) {
113 // this is for the predicate version or if a choice() is present
114 ChoiceType choice = null;
115 for (ProcessorType processor : answer.getOutputs()) {
116 if (processor instanceof ChoiceType) {
117 // special cases for predicates (choices)
118 choice = (ChoiceType) processor;
119
120 // for the predicated version we add the proceed() to otherwise()
121 // before knowing if stop() will follow, so let's make a small adjustment
122 if (usePredicate.booleanValue() && getStopIntercept().booleanValue()) {
123 WhenType when = choice.getWhenClauses().get(0);
124 when.getOutputs().remove(this.getProceed());
125 }
126
127 // add proceed to the when clause
128 addProceedProxy(this.getProceed(), answer.getProceed(),
129 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate.booleanValue() && !getStopIntercept().booleanValue());
130
131 // force adding a proceed at the end (otherwise) if its not a stop type
132 addProceedProxy(this.getProceed(), answer.getProceed(), choice.getOtherwise(), !getStopIntercept().booleanValue());
133
134 if (getStopIntercept().booleanValue()) {
135 // must add proceed to when clause if stop is explictiy declared, otherwise when the
136 // predicate test fails then there is no proceed
137 // See example: InterceptorSimpleRouteTest (City Paris is never proceeded)
138 addProceedProxy(this.getProceed(), answer.getProceed(),
139 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate.booleanValue());
140 }
141
142 break;
143 }
144 }
145 if (choice == null) {
146 // force adding a proceed at the end if its not a stop type
147 addProceedProxy(this.getProceed(), answer.getProceed(), answer, !getStopIntercept().booleanValue());
148 }
149 }
150
151 return answer;
152 }
153
154 private void addProceedProxy(ProceedType orig, ProceedType proxy, ProcessorType<?> processor, boolean force) {
155 int index = processor.getOutputs().indexOf(orig);
156 if (index >= 0) {
157 processor.addOutput(proxy);
158 // replace original proceed with proxy
159 List<ProcessorType<?>> outs = processor.getOutputs();
160 outs.remove(proxy);
161 outs.set(index, proxy);
162 } else if (force) {
163 processor.addOutput(proxy);
164 }
165 }
166
167 public void setStopIntercept(Boolean stop) {
168 this.stopIntercept = stop;
169 }
170
171 public Boolean getStopIntercept() {
172 return stopIntercept;
173 }
174
175 }