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: 896185 $
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 boolean isAbstract() {
074            return true;
075        }
076    
077        @Override
078        public Processor createProcessor(RouteContext routeContext) throws Exception {
079            Processor childProcessor = createOutputsProcessor(routeContext);
080    
081            // wrap the on completion route in a unit of work processor
082            childProcessor = new UnitOfWorkProcessor(routeContext, childProcessor);
083    
084            Predicate when = null;
085            if (onWhen != null) {
086                when = onWhen.getExpression().createPredicate(routeContext);
087            }
088    
089            if (onCompleteOnly && onFailureOnly) {
090                throw new IllegalArgumentException("Both onCompleteOnly and onFailureOnly cannot be true. Only one of them can be true. On node: " + this);
091            }
092    
093            return new OnCompletionProcessor(childProcessor, onCompleteOnly, onFailureOnly, when);
094        }
095    
096        /**
097         * Removes all existing {@link org.apache.camel.model.OnCompletionDefinition} from the definition.
098         * <p/>
099         * This is used to let route scoped <tt>onCompletion</tt> overrule any global <tt>onCompletion</tt>.
100         * Hence we remove all existing as they are global.
101         *
102         * @param definition the parent definition that is the route
103         */
104        @SuppressWarnings("unchecked")
105        public void removeAllOnCompletionDefinition(ProcessorDefinition definition) {
106            for (Iterator<ProcessorDefinition> it = definition.getOutputs().iterator(); it.hasNext();) {
107                ProcessorDefinition out = it.next();
108                if (out instanceof OnCompletionDefinition) {
109                    it.remove();
110                }
111            }
112        }
113    
114        @Override
115        public ProcessorDefinition<? extends ProcessorDefinition<?>> end() {
116            // pop parent block, as we added our self as block to parent when synchronized was defined in the route
117            getParent().popBlock();
118            return super.end();
119        }
120    
121        /**
122         * Will only synchronize when the {@link org.apache.camel.Exchange} completed successfully (no errors).
123         *
124         * @return the builder
125         */
126        public OnCompletionDefinition onCompleteOnly() {
127            // must define return type as OutputDefinition and not this type to avoid end user being able
128            // to invoke onFailureOnly/onCompleteOnly more than once
129            setOnCompleteOnly(Boolean.TRUE);
130            setOnFailureOnly(Boolean.FALSE);
131            return this;
132        }
133    
134        /**
135         * Will only synchronize when the {@link org.apache.camel.Exchange} ended with failure (exception or FAULT message).
136         *
137         * @return the builder
138         */
139        public OnCompletionDefinition onFailureOnly() {
140            // must define return type as OutputDefinition and not this type to avoid end user being able
141            // to invoke onFailureOnly/onCompleteOnly more than once
142            setOnCompleteOnly(Boolean.FALSE);
143            setOnFailureOnly(Boolean.TRUE);
144            return this;
145        }
146    
147        /**
148         * Sets an additional predicate that should be true before the onCompletion is triggered.
149         * <p/>
150         * To be used for fine grained controlling whether a completion callback should be invoked or not
151         *
152         * @param predicate predicate that determines true or false
153         * @return the builder
154         */
155        public OnCompletionDefinition onWhen(Predicate predicate) {
156            setOnWhen(new WhenDefinition(predicate));
157            return this;
158        }
159    
160        /**
161         * Creates an expression to configure an additional predicate that should be true before the
162         * onCompletion is triggered.
163         * <p/>
164         * To be used for fine grained controlling whether a completion callback should be invoked or not
165         *
166         * @return the expression clause to configure
167         */
168        public ExpressionClause<OnCompletionDefinition> onWhen() {
169            onWhen = new WhenDefinition();
170            ExpressionClause<OnCompletionDefinition> clause = new ExpressionClause<OnCompletionDefinition>(this);
171            onWhen.setExpression(clause);
172            return clause;
173        }
174    
175    
176        public List<ProcessorDefinition> getOutputs() {
177            return outputs;
178        }
179    
180        public void setOutputs(List<ProcessorDefinition> outputs) {
181            this.outputs = outputs;
182        }
183    
184        public Boolean getOnCompleteOnly() {
185            return onCompleteOnly;
186        }
187    
188        public void setOnCompleteOnly(Boolean onCompleteOnly) {
189            this.onCompleteOnly = onCompleteOnly;
190        }
191    
192        public Boolean getOnFailureOnly() {
193            return onFailureOnly;
194        }
195    
196        public void setOnFailureOnly(Boolean onFailureOnly) {
197            this.onFailureOnly = onFailureOnly;
198        }
199    
200        public WhenDefinition getOnWhen() {
201            return onWhen;
202        }
203    
204        public void setOnWhen(WhenDefinition onWhen) {
205            this.onWhen = onWhen;
206        }
207    
208    }