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