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    
022    import javax.xml.bind.annotation.XmlAccessType;
023    import javax.xml.bind.annotation.XmlAccessorType;
024    import javax.xml.bind.annotation.XmlElement;
025    import javax.xml.bind.annotation.XmlElementRef;
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.spi.RouteContext;
036    import org.apache.camel.util.CastUtils;
037    import org.apache.camel.util.ObjectHelper;
038    import static org.apache.camel.builder.PredicateBuilder.toPredicate;
039    
040    /**
041     * Represents an XML <catch/> element
042     *
043     * @version $Revision: 888719 $
044     */
045    @XmlRootElement(name = "doCatch")
046    @XmlAccessorType(XmlAccessType.FIELD)
047    public class CatchDefinition extends ProcessorDefinition<CatchDefinition> {
048        @XmlElement(name = "exception")
049        private List<String> exceptions = new ArrayList<String>();
050        @XmlElement(name = "onWhen", required = false)
051        private WhenDefinition onWhen;
052        @XmlElement(name = "handled", required = false)
053        private ExpressionSubElementDefinition handled;
054        @XmlElementRef
055        private List<ProcessorDefinition> outputs = new ArrayList<ProcessorDefinition>();
056        @XmlTransient
057        private List<Class> exceptionClasses;
058        @XmlTransient
059        private Predicate handledPolicy;
060    
061        public CatchDefinition() {
062        }
063    
064        public CatchDefinition(List<Class> exceptionClasses) {
065            this.exceptionClasses = exceptionClasses;
066        }
067    
068        public CatchDefinition(Class exceptionType) {
069            exceptionClasses = new ArrayList<Class>();
070            exceptionClasses.add(exceptionType);
071        }
072    
073        @Override
074        public String toString() {
075            return "DoCatch[ " + getExceptionClasses() + " -> " + getOutputs() + "]";
076        }
077    
078        @Override
079        public String getShortName() {
080            return "doCatch";
081        }
082    
083        @Override
084        public String getLabel() {
085            return getExceptionClasses().toString();
086        }
087    
088        @Override
089        public CatchProcessor createProcessor(RouteContext routeContext) throws Exception {
090            // must have at least one exception
091            if (getExceptionClasses().isEmpty()) {
092                throw new IllegalArgumentException("At least one Exception must be configured to catch");
093            }
094    
095            Processor childProcessor = routeContext.createProcessor(this);
096    
097            Predicate when = null;
098            if (onWhen != null) {
099                when = onWhen.getExpression().createPredicate(routeContext);
100            }
101    
102            Predicate handle = handledPolicy;
103            if (handled != null) {
104                handle = handled.createPredicate(routeContext);
105            }
106    
107            return new CatchProcessor(getExceptionClasses(), childProcessor, when, handle);
108        }
109    
110        public List<ProcessorDefinition> getOutputs() {
111            return outputs;
112        }
113    
114        public void setOutputs(List<ProcessorDefinition> outputs) {
115            this.outputs = outputs;
116        }
117    
118        public List<Class> getExceptionClasses() {
119            if (exceptionClasses == null) {
120                exceptionClasses = createExceptionClasses();
121            }
122            return exceptionClasses;
123        }
124    
125        public void setExceptionClasses(List<Class> exceptionClasses) {
126            this.exceptionClasses = exceptionClasses;
127        }
128        
129        // Fluent API
130        //-------------------------------------------------------------------------
131        /**
132         * Sets the exceptionClasses of the CatchType
133         *
134         * @param exceptionClasses  a list of the exception classes
135         * @return the builder
136         */
137        public CatchDefinition exceptionClasses(List<Class> exceptionClasses) {
138            setExceptionClasses(exceptionClasses);
139            return this;
140        }
141        
142        /**
143         * Sets an additional predicate that should be true before the onCatch is triggered.
144         * <p/>
145         * To be used for fine grained controlling whether a thrown exception should be intercepted
146         * by this exception type or not.
147         *
148         * @param predicate  predicate that determines true or false
149         * @return the builder
150         */
151        public CatchDefinition onWhen(Predicate predicate) {
152            setOnWhen(new WhenDefinition(predicate));
153            return this;
154        }
155    
156        /**
157         * Creates an expression to configure an additional predicate that should be true before the
158         * onCatch is triggered.
159         * <p/>
160         * To be used for fine grained controlling whether a thrown exception should be intercepted
161         * by this exception type or not.
162         *
163         * @return the expression clause to configure
164         */
165        public ExpressionClause<CatchDefinition> onWhen() {
166            onWhen = new WhenDefinition();
167            ExpressionClause<CatchDefinition> clause = new ExpressionClause<CatchDefinition>(this);
168            onWhen.setExpression(clause);
169            return clause;
170        }
171    
172        /**
173         * Sets whether the exchange should be marked as handled or not.
174         *
175         * @param handled  handled or not
176         * @return the builder
177         */
178        public CatchDefinition handled(boolean handled) {
179            Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(handled));
180            return handled(expression);
181        }
182    
183        /**
184         * Sets whether the exchange should be marked as handled or not.
185         *
186         * @param handled  predicate that determines true or false
187         * @return the builder
188         */
189        public CatchDefinition handled(Predicate handled) {
190            setHandledPolicy(handled);
191            return this;
192        }
193    
194        /**
195         * Sets whether the exchange should be marked as handled or not.
196         *
197         * @param handled  expression that determines true or false
198         * @return the builder
199         */
200        public CatchDefinition handled(Expression handled) {
201            setHandledPolicy(toPredicate(handled));
202            return this;
203        }
204    
205        /**
206         * Sets the exception class that the CatchType want to catch
207         *
208         * @param exception  the exception of class
209         * @return the builder
210         */
211        public CatchDefinition exceptionClasses(Class exception) {
212            List<Class> list = getExceptionClasses();
213            list.add(exception);
214            return this;
215        }
216    
217        public List<String> getExceptions() {
218            return exceptions;
219        }
220    
221        public void setExceptions(List<String> exceptions) {
222            this.exceptions = exceptions;
223        }
224    
225        public WhenDefinition getOnWhen() {
226            return onWhen;
227        }
228    
229        public void setOnWhen(WhenDefinition onWhen) {
230            this.onWhen = onWhen;
231        }
232    
233        public Predicate getHandledPolicy() {
234            return handledPolicy;
235        }
236    
237        public void setHandledPolicy(Predicate handledPolicy) {
238            this.handledPolicy = handledPolicy;
239        }
240    
241        public ExpressionSubElementDefinition getHandled() {
242            return handled;
243        }
244    
245        public void setHandled(ExpressionSubElementDefinition handled) {
246            this.handled = handled;
247        }
248    
249        protected List<Class> createExceptionClasses() {
250            List<String> list = getExceptions();
251            List<Class> answer = new ArrayList<Class>(list.size());
252            for (String name : list) {
253                Class<Exception> type = CastUtils.cast(ObjectHelper.loadClass(name, getClass().getClassLoader()));
254                answer.add(type);
255            }
256            return answer;
257        }
258    }