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.Arrays;
021    import java.util.Iterator;
022    import java.util.List;
023    
024    import javax.xml.bind.annotation.XmlAccessType;
025    import javax.xml.bind.annotation.XmlAccessorType;
026    import javax.xml.bind.annotation.XmlRootElement;
027    import javax.xml.bind.annotation.XmlTransient;
028    
029    import org.apache.camel.Expression;
030    import org.apache.camel.Predicate;
031    import org.apache.camel.Processor;
032    import org.apache.camel.builder.ExpressionBuilder;
033    import org.apache.camel.builder.ExpressionClause;
034    import org.apache.camel.processor.CatchProcessor;
035    import org.apache.camel.processor.TryProcessor;
036    import org.apache.camel.spi.RouteContext;
037    import org.apache.camel.util.ProcessorDefinitionHelper;
038    import static org.apache.camel.builder.PredicateBuilder.toPredicate;
039    
040    /**
041     * Represents an XML <try/> element
042     *
043     * @version $Revision: 766610 $
044     */
045    @XmlRootElement(name = "doTry")
046    @XmlAccessorType(XmlAccessType.FIELD)
047    public class TryDefinition extends OutputDefinition<TryDefinition> {
048        @XmlTransient
049        private List<CatchDefinition> catchClauses;
050        @XmlTransient
051        private FinallyDefinition finallyClause;
052        @XmlTransient
053        private boolean initialized;
054        @XmlTransient
055        private List<ProcessorDefinition> outputsWithoutCatches;
056    
057        @Override
058        public String toString() {
059            return "DoTry[" + getOutputs() + "]";
060        }
061    
062        @Override
063        public String getShortName() {
064            return "doTry";
065        }
066    
067        @Override
068        public Processor createProcessor(RouteContext routeContext) throws Exception {
069            Processor tryProcessor = createOutputsProcessor(routeContext, getOutputsWithoutCatches());
070    
071            Processor finallyProcessor = null;
072            if (finallyClause != null) {
073                finallyProcessor = finallyClause.createProcessor(routeContext);
074            }
075    
076            List<CatchProcessor> catchProcessors = new ArrayList<CatchProcessor>();
077            if (catchClauses != null) {
078                for (CatchDefinition catchClause : catchClauses) {
079                    catchProcessors.add(catchClause.createProcessor(routeContext));
080                }
081            }
082    
083            return new TryProcessor(tryProcessor, catchProcessors, finallyProcessor);
084        }
085    
086        // Fluent API
087        // -------------------------------------------------------------------------
088    
089        /**
090         * Handles the given exception(s)
091         *
092         * @param exceptionType  the exception(s)
093         * @return the try builder
094         */
095        public TryDefinition doCatch(Class... exceptionType) {
096            popBlock();
097            List<Class> list = Arrays.asList(exceptionType);
098            CatchDefinition answer = new CatchDefinition(list);
099            addOutput(answer);
100            pushBlock(answer);
101            return this;
102        }
103    
104        /**
105         * Sets an additional predicate that should be true before the onCatch is triggered.
106         * <p/>
107         * To be used for fine grained controlling whether a thrown exception should be intercepted
108         * by this exception type or not.
109         *
110         * @param predicate  predicate that determines true or false
111         * @return the builder
112         */
113        public TryDefinition onWhen(Predicate predicate) {
114            // we must use a delegate so we can use the fluent builder based on TryDefinition
115            // to configure all with try .. catch .. finally
116            // set the onWhen predicate on all the catch definitions
117            Iterator<CatchDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(getOutputs(), CatchDefinition.class);
118            while (it.hasNext()) {
119                CatchDefinition doCatch = it.next();
120                doCatch.setOnWhen(new WhenDefinition(predicate));
121            }
122            return this;
123        }
124    
125        /**
126         * Creates an expression to configure an additional predicate that should be true before the
127         * onCatch is triggered.
128         * <p/>
129         * To be used for fine grained controlling whether a thrown exception should be intercepted
130         * by this exception type or not.
131         *
132         * @return the expression clause to configure
133         */
134        public ExpressionClause<TryDefinition> onWhen() {
135            // we must use a delegate so we can use the fluent builder based on TryDefinition
136            // to configure all with try .. catch .. finally
137            WhenDefinition answer = new WhenDefinition();
138            // set the onWhen definition on all the catch definitions
139            Iterator<CatchDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(getOutputs(), CatchDefinition.class);
140            while (it.hasNext()) {
141                CatchDefinition doCatch = it.next();
142                doCatch.setOnWhen(answer);
143            }
144            // return a expression clause as builder to set the predicate on the onWhen definition
145            ExpressionClause<TryDefinition> clause = new ExpressionClause<TryDefinition>(this);
146            answer.setExpression(clause);
147            return clause;
148        }
149    
150        /**
151         * Sets whether the exchange should be marked as handled or not.
152         *
153         * @param handled  handled or not
154         * @return the builder
155         */
156        public TryDefinition handled(boolean handled) {
157            Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(handled));
158            return handled(expression);
159        }
160    
161        /**
162         * Sets whether the exchange should be marked as handled or not.
163         *
164         * @param handled  predicate that determines true or false
165         * @return the builder
166         */
167        public TryDefinition handled(Predicate handled) {
168            // we must use a delegate so we can use the fluent builder based on TryDefinition
169            // to configure all with try .. catch .. finally
170            // set the handled on all the catch definitions
171            Iterator<CatchDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(getOutputs(), CatchDefinition.class);
172            while (it.hasNext()) {
173                CatchDefinition doCatch = it.next();
174                doCatch.setHandledPolicy(handled);
175            }
176            return this;
177        }
178    
179        /**
180         * Sets whether the exchange should be marked as handled or not.
181         *
182         * @param handled  expression that determines true or false
183         * @return the builder
184         */
185        public TryDefinition handled(Expression handled) {
186            return handled(toPredicate(handled));
187        }
188    
189        /**
190         * The finally block for a given handle
191         *
192         * @return  the try builder
193         */
194        public TryDefinition doFinally() {
195            popBlock();
196            FinallyDefinition answer = new FinallyDefinition();
197            addOutput(answer);
198            pushBlock(answer);
199            return this;
200        }
201    
202        @Override
203        public ProcessorDefinition<? extends ProcessorDefinition> end() {
204            popBlock();
205            return super.end();
206        }
207    
208        // Properties
209        // -------------------------------------------------------------------------
210    
211        public List<CatchDefinition> getCatchClauses() {
212            if (catchClauses == null) {
213                checkInitialized();
214            }
215            return catchClauses;
216        }
217    
218        public FinallyDefinition getFinallyClause() {
219            if (finallyClause == null) {
220                checkInitialized();
221            }
222            return finallyClause;
223        }
224    
225        public List<ProcessorDefinition> getOutputsWithoutCatches() {
226            if (outputsWithoutCatches == null) {
227                checkInitialized();
228            }
229            return outputsWithoutCatches;
230        }
231    
232        public void setOutputs(List<ProcessorDefinition> outputs) {
233            initialized = false;
234            super.setOutputs(outputs);
235        }
236    
237        @Override
238        public void addOutput(ProcessorDefinition output) {
239            initialized = false;
240            super.addOutput(output);
241        }
242    
243        /**
244         * Checks whether or not this object has been initialized
245         */
246        protected void checkInitialized() {
247            if (!initialized) {
248                initialized = true;
249                outputsWithoutCatches = new ArrayList<ProcessorDefinition>();
250                catchClauses = new ArrayList<CatchDefinition>();
251                finallyClause = null;
252    
253                for (ProcessorDefinition output : outputs) {
254                    if (output instanceof CatchDefinition) {
255                        catchClauses.add((CatchDefinition)output);
256                    } else if (output instanceof FinallyDefinition) {
257                        if (finallyClause != null) {
258                            throw new IllegalArgumentException("Multiple finally clauses added: " + finallyClause
259                                                               + " and " + output);
260                        } else {
261                            finallyClause = (FinallyDefinition)output;
262                        }
263                    } else {
264                        outputsWithoutCatches.add(output);
265                    }
266                }
267            }
268        }
269    
270    }