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