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: 50606 $
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 Processor createProcessor(RouteContext routeContext) throws Exception {
065 Interceptor interceptor = new Interceptor();
066 routeContext.intercept(interceptor);
067
068 final Processor interceptRoute = createOutputsProcessor(routeContext);
069 interceptor.setInterceptorLogic(interceptRoute);
070
071 return interceptor;
072 }
073
074 /**
075 * Applies this interceptor only if the given predicate is true
076 */
077 public ChoiceType when(Predicate predicate) {
078 usePredicate = Boolean.TRUE;
079 ChoiceType choice = choice().when(PredicateBuilder.not(predicate));
080 choice.addOutput(proceed);
081 return choice.otherwise();
082 }
083
084 public ProceedType getProceed() {
085 return proceed;
086 }
087
088 public void stopIntercept() {
089 setStopIntercept(Boolean.TRUE);
090 }
091
092 @XmlElement(name = "stop", required = false)
093 public void setStop(String elementValue /* not used */) {
094 stopIntercept();
095 }
096
097 public InterceptType createProxy() {
098 InterceptType answer = new InterceptType();
099 answer.getOutputs().addAll(this.getOutputs());
100
101 answer.setStopIntercept(getStopIntercept());
102
103 // hack: now we need to replace the proceed of the proxy with its own
104 // a bit ugly, operating based on the assumption that the proceed is
105 // in its outputs (if proceed() was called) and/or in the
106 // outputs of the otherwise or last when clause for the predicated version.
107 if (answer.getOutputs().size() > 0) {
108 // this is for the predicate version or if a choice() is present
109 ChoiceType choice = null;
110 for (ProcessorType processor : answer.getOutputs()) {
111 if (processor instanceof ChoiceType) {
112 // special cases for predicates (choices)
113 choice = (ChoiceType) processor;
114
115 // for the predicated version we add the proceed() to otherwise()
116 // before knowing if stop() will follow, so let's make a small adjustment
117 if (usePredicate.booleanValue() && getStopIntercept().booleanValue()) {
118 WhenType when = choice.getWhenClauses().get(0);
119 when.getOutputs().remove(this.getProceed());
120 }
121
122 // add proceed to the when clause
123 addProceedProxy(this.getProceed(), answer.getProceed(),
124 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate.booleanValue() && !getStopIntercept().booleanValue());
125
126 // force adding a proceed at the end (otherwise) if its not a stop type
127 addProceedProxy(this.getProceed(), answer.getProceed(), choice.getOtherwise(), !getStopIntercept().booleanValue());
128
129 if (getStopIntercept().booleanValue()) {
130 // must add proceed to when clause if stop is explictiy declared, otherwise when the
131 // predicate test fails then there is no proceed
132 // See example: InterceptorSimpleRouteTest (City Paris is never proceeded)
133 addProceedProxy(this.getProceed(), answer.getProceed(),
134 choice.getWhenClauses().get(choice.getWhenClauses().size() - 1), usePredicate.booleanValue());
135 }
136
137 break;
138 }
139 }
140 if (choice == null) {
141 // force adding a proceed at the end if its not a stop type
142 addProceedProxy(this.getProceed(), answer.getProceed(), answer, !getStopIntercept().booleanValue());
143 }
144 }
145
146 return answer;
147 }
148
149 private void addProceedProxy(ProceedType orig, ProceedType proxy, ProcessorType<?> processor, boolean force) {
150 int index = processor.getOutputs().indexOf(orig);
151 if (index >= 0) {
152 processor.addOutput(proxy);
153 // replace original proceed with proxy
154 List<ProcessorType<?>> outs = processor.getOutputs();
155 outs.remove(proxy);
156 outs.set(index, proxy);
157 } else if (force) {
158 processor.addOutput(proxy);
159 }
160 }
161
162 public void setStopIntercept(Boolean stop) {
163 this.stopIntercept = stop;
164 }
165
166 public Boolean getStopIntercept() {
167 return stopIntercept;
168 }
169
170 }