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