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