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 }