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.Iterator;
021    import java.util.List;
022    import javax.xml.bind.annotation.XmlAccessType;
023    import javax.xml.bind.annotation.XmlAccessorType;
024    import javax.xml.bind.annotation.XmlAttribute;
025    import javax.xml.bind.annotation.XmlElement;
026    import javax.xml.bind.annotation.XmlElementRef;
027    import javax.xml.bind.annotation.XmlRootElement;
028    
029    import org.apache.camel.Predicate;
030    import org.apache.camel.Processor;
031    import org.apache.camel.builder.ExpressionClause;
032    import org.apache.camel.processor.OnCompletionProcessor;
033    import org.apache.camel.processor.UnitOfWorkProcessor;
034    import org.apache.camel.spi.RouteContext;
035    
036    /**
037     * Represents an XML <onCompletion/> element
038     *
039     * @version $Revision: 788766 $
040     */
041    @XmlRootElement(name = "onCompletion")
042    @XmlAccessorType(XmlAccessType.FIELD)
043    public class OnCompletionDefinition extends ProcessorDefinition<ProcessorDefinition> {
044    
045        @XmlAttribute(required = false)
046        private Boolean onCompleteOnly = Boolean.FALSE;
047        @XmlAttribute(required = false)
048        private Boolean onFailureOnly = Boolean.FALSE;
049        @XmlElement(name = "onWhen", required = false)
050        private WhenDefinition onWhen;
051        @XmlElementRef
052        private List<ProcessorDefinition> outputs = new ArrayList<ProcessorDefinition>();
053    
054        public OnCompletionDefinition() {
055        }
056    
057        @Override
058        public String toString() {
059            return "onCompletion[" + getOutputs() + "]";
060        }
061    
062        @Override
063        public String getShortName() {
064            return "onCompletion";
065        }
066    
067        @Override
068        public String getLabel() {
069            return "onCompletion";
070        }
071    
072        @Override
073        public Processor createProcessor(RouteContext routeContext) throws Exception {
074            Processor childProcessor = createOutputsProcessor(routeContext);
075    
076            // wrap the on completion route in a unit of work processor
077            childProcessor = new UnitOfWorkProcessor(childProcessor);
078    
079            Predicate when = null;
080            if (onWhen != null) {
081                when = onWhen.getExpression().createPredicate(routeContext);
082            }
083    
084            if (onCompleteOnly && onFailureOnly) {
085                throw new IllegalArgumentException("Both onCompleteOnly and onFailureOnly cannot be true. Only one of them can be true. On node: " + this);
086            }
087    
088            return new OnCompletionProcessor(childProcessor, onCompleteOnly, onFailureOnly, when);
089        }
090    
091        /**
092         * Removes all existing {@link org.apache.camel.model.OnCompletionDefinition} from the defintion.
093         * <p/>
094         * This is used to let route scoped <tt>onCompletion</tt> overrule any global <tt>onCompletion</tt>.
095         * Hence we remove all existing as they are global.
096         *
097         * @param definition the parent defintion that is the route
098         */
099        @SuppressWarnings("unchecked")
100        public void removeAllOnCompletionDefinition(ProcessorDefinition definition) {
101            for (Iterator<ProcessorDefinition> it = definition.getOutputs().iterator(); it.hasNext();) {
102                ProcessorDefinition out = it.next();
103                if (out instanceof OnCompletionDefinition) {
104                    it.remove();
105                }
106            }
107        }
108    
109        @Override
110        public ProcessorDefinition<? extends ProcessorDefinition> end() {
111            // pop parent block, as we added outself as block to parent when synchronized was defined in the route
112            getParent().popBlock();
113            return super.end();
114        }
115    
116        /**
117         * Will only synchronize when the {@link org.apache.camel.Exchange} completed succesfully (no errors).
118         *
119         * @return the builder
120         */
121        public OnCompletionDefinition onCompleteOnly() {
122            // must define return type as OutputDefinition and not this type to avoid end user being able
123            // to invoke onFailureOnly/onCompleteOnly more than once
124            setOnCompleteOnly(Boolean.TRUE);
125            setOnFailureOnly(Boolean.FALSE);
126            return this;
127        }
128    
129        /**
130         * Will only synchronize when the {@link org.apache.camel.Exchange} ended with failure (exception or FAULT message).
131         *
132         * @return the builder
133         */
134        public OnCompletionDefinition onFailureOnly() {
135            // must define return type as OutputDefinition and not this type to avoid end user being able
136            // to invoke onFailureOnly/onCompleteOnly more than once
137            setOnCompleteOnly(Boolean.FALSE);
138            setOnFailureOnly(Boolean.TRUE);
139            return this;
140        }
141    
142        /**
143         * Sets an additional predicate that should be true before the onCompletion is triggered.
144         * <p/>
145         * To be used for fine grained controlling whether a completion callback should be invoked or not
146         *
147         * @param predicate predicate that determines true or false
148         * @return the builder
149         */
150        public OnCompletionDefinition onWhen(Predicate predicate) {
151            setOnWhen(new WhenDefinition(predicate));
152            return this;
153        }
154    
155        /**
156         * Creates an expression to configure an additional predicate that should be true before the
157         * onCompletion is triggered.
158         * <p/>
159         * To be used for fine grained controlling whether a completion callback should be invoked or not
160         *
161         * @return the expression clause to configure
162         */
163        public ExpressionClause<OnCompletionDefinition> onWhen() {
164            onWhen = new WhenDefinition();
165            ExpressionClause<OnCompletionDefinition> clause = new ExpressionClause<OnCompletionDefinition>(this);
166            onWhen.setExpression(clause);
167            return clause;
168        }
169    
170    
171        public List<ProcessorDefinition> getOutputs() {
172            return outputs;
173        }
174    
175        public void setOutputs(List<ProcessorDefinition> outputs) {
176            this.outputs = outputs;
177        }
178    
179        public Boolean getOnCompleteOnly() {
180            return onCompleteOnly;
181        }
182    
183        public void setOnCompleteOnly(Boolean onCompleteOnly) {
184            this.onCompleteOnly = onCompleteOnly;
185        }
186    
187        public Boolean getOnFailureOnly() {
188            return onFailureOnly;
189        }
190    
191        public void setOnFailureOnly(Boolean onFailureOnly) {
192            this.onFailureOnly = onFailureOnly;
193        }
194    
195        public WhenDefinition getOnWhen() {
196            return onWhen;
197        }
198    
199        public void setOnWhen(WhenDefinition onWhen) {
200            this.onWhen = onWhen;
201        }
202    
203    }