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 }