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 }