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.CamelContext;
027 import org.apache.camel.Predicate;
028 import org.apache.camel.Processor;
029 import org.apache.camel.processor.Pipeline;
030 import org.apache.camel.spi.InterceptStrategy;
031 import org.apache.camel.spi.RouteContext;
032
033 /**
034 * Represents an XML <intercept/> element
035 *
036 * @version $Revision: 896185 $
037 */
038 @XmlRootElement(name = "intercept")
039 @XmlAccessorType(XmlAccessType.FIELD)
040 public class InterceptDefinition extends OutputDefinition<ProcessorDefinition> {
041
042 // TODO: support stop later (its a bit hard as it needs to break entire processing of route)
043
044 @XmlTransient
045 protected Processor output;
046
047 @XmlTransient
048 protected final List<Processor> intercepted = new ArrayList<Processor>();
049
050 public InterceptDefinition() {
051 }
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 boolean isAbstract() {
070 return true;
071 }
072
073 @Override
074 public Processor createProcessor(final RouteContext routeContext) throws Exception {
075 // create the output processor
076 output = createOutputsProcessor(routeContext);
077
078 // add the output as a intercept strategy to the route context so its invoked on each processing step
079 routeContext.getInterceptStrategies().add(new InterceptStrategy() {
080 private Processor interceptedTarget;
081
082 public Processor wrapProcessorInInterceptors(CamelContext context, ProcessorDefinition definition,
083 Processor target, Processor nextTarget) throws Exception {
084 // prefer next target over target as next target is the real target
085 interceptedTarget = nextTarget != null ? nextTarget : target;
086
087 // remember the target that was intercepted
088 intercepted.add(interceptedTarget);
089
090 if (interceptedTarget != null) {
091 // wrap in a pipeline so we continue routing to the next
092 List<Processor> list = new ArrayList<Processor>(2);
093 list.add(output);
094 list.add(interceptedTarget);
095 return new Pipeline(list);
096 } else {
097 return output;
098 }
099 }
100
101 @Override
102 public String toString() {
103 return "intercept[" + (interceptedTarget != null ? interceptedTarget : output) + "]";
104 }
105 });
106
107 // remove me from the route so I am not invoked in a regular route path
108 routeContext.getRoute().getOutputs().remove(this);
109 // and return no processor to invoke next from me
110 return null;
111 }
112
113 /**
114 * Applies this interceptor only if the given predicate is true
115 *
116 * @param predicate the predicate
117 * @return the builder
118 */
119 public ChoiceDefinition when(Predicate predicate) {
120 return choice().when(predicate);
121 }
122
123 /**
124 * This method is <b>only</b> for handling some post configuration
125 * that is needed from the Spring DSL side as JAXB does not invoke the fluent
126 * builders, so we need to manually handle this afterwards, and since this is
127 * an interceptor it has to do a bit of magic logic to fixup to handle predicates
128 * with or without proceed/stop set as well.
129 */
130 public void afterPropertiesSet() {
131 if (getOutputs().size() == 0) {
132 // no outputs
133 return;
134 }
135
136 ProcessorDefinition first = getOutputs().get(0);
137 if (first instanceof WhenDefinition) {
138 WhenDefinition when = (WhenDefinition) first;
139 // move this outputs to the when, expect the first one
140 // as the first one is the interceptor itself
141 for (int i = 1; i < outputs.size(); i++) {
142 ProcessorDefinition out = outputs.get(i);
143 when.addOutput(out);
144 }
145 // remove the moved from the original output, by just keeping the first one
146 ProcessorDefinition keep = outputs.get(0);
147 clearOutput();
148 outputs.add(keep);
149 }
150 }
151
152 public Processor getInterceptedProcessor(int index) {
153 // avoid out of bounds
154 if (index <= intercepted.size() - 1) {
155 return intercepted.get(index);
156 } else {
157 return null;
158 }
159 }
160 }