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 }