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 */ 017package org.apache.camel.model; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import javax.xml.bind.annotation.XmlAccessType; 023import javax.xml.bind.annotation.XmlAccessorType; 024import javax.xml.bind.annotation.XmlElement; 025import javax.xml.bind.annotation.XmlElementRef; 026import javax.xml.bind.annotation.XmlRootElement; 027import javax.xml.bind.annotation.XmlTransient; 028 029import org.apache.camel.CamelContext; 030import org.apache.camel.Expression; 031import org.apache.camel.Predicate; 032import org.apache.camel.Processor; 033import org.apache.camel.builder.ExpressionBuilder; 034import org.apache.camel.processor.CatchProcessor; 035import org.apache.camel.spi.AsPredicate; 036import org.apache.camel.spi.Metadata; 037import org.apache.camel.spi.RouteContext; 038import org.apache.camel.util.ExpressionToPredicateAdapter; 039 040/** 041 * Catches exceptions as part of a try, catch, finally block 042 * 043 * @version 044 */ 045@Metadata(label = "error") 046@XmlRootElement(name = "doCatch") 047@XmlAccessorType(XmlAccessType.FIELD) 048public class CatchDefinition extends ProcessorDefinition<CatchDefinition> { 049 @XmlElement(name = "exception") 050 private List<String> exceptions = new ArrayList<>(); 051 @XmlElement(name = "onWhen") @AsPredicate 052 private WhenDefinition onWhen; 053 @XmlElement(name = "handled") @AsPredicate 054 @Deprecated 055 private ExpressionSubElementDefinition handled; 056 @XmlElementRef 057 private List<ProcessorDefinition<?>> outputs = new ArrayList<>(); 058 @XmlTransient 059 private List<Class<? extends Throwable>> exceptionClasses; 060 @XmlTransient 061 private Predicate handledPolicy; 062 063 public CatchDefinition() { 064 } 065 066 public CatchDefinition(List<Class<? extends Throwable>> exceptionClasses) { 067 this.exceptionClasses = exceptionClasses; 068 } 069 070 public CatchDefinition(Class<? extends Throwable> exceptionType) { 071 exceptionClasses = new ArrayList<>(); 072 exceptionClasses.add(exceptionType); 073 } 074 075 @Override 076 public String toString() { 077 return "DoCatch[ " + getExceptionClasses() + " -> " + getOutputs() + "]"; 078 } 079 080 @Override 081 public String getShortName() { 082 return "doCatch"; 083 } 084 085 @Override 086 public String getLabel() { 087 return "doCatch[ " + getExceptionClasses() + "]"; 088 } 089 090 @Override 091 public CatchProcessor createProcessor(RouteContext routeContext) throws Exception { 092 // create and load exceptions if not done 093 if (exceptionClasses == null) { 094 exceptionClasses = createExceptionClasses(routeContext.getCamelContext()); 095 } 096 097 // must have at least one exception 098 if (exceptionClasses.isEmpty()) { 099 throw new IllegalArgumentException("At least one Exception must be configured to catch"); 100 } 101 102 // parent must be a try 103 if (!(getParent() instanceof TryDefinition)) { 104 throw new IllegalArgumentException("This doCatch should have a doTry as its parent on " + this); 105 } 106 107 // do catch does not mandate a child processor 108 Processor childProcessor = this.createChildProcessor(routeContext, false); 109 110 Predicate when = null; 111 if (onWhen != null) { 112 when = onWhen.getExpression().createPredicate(routeContext); 113 } 114 115 Predicate handle = handledPolicy; 116 if (handled != null) { 117 handle = handled.createPredicate(routeContext); 118 } 119 120 return new CatchProcessor(exceptionClasses, childProcessor, when, handle); 121 } 122 123 @Override 124 public List<ProcessorDefinition<?>> getOutputs() { 125 return outputs; 126 } 127 128 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 129 this.outputs = outputs; 130 } 131 132 public boolean isOutputSupported() { 133 return true; 134 } 135 136 public List<Class<? extends Throwable>> getExceptionClasses() { 137 return exceptionClasses; 138 } 139 140 public void setExceptionClasses(List<Class<? extends Throwable>> exceptionClasses) { 141 this.exceptionClasses = exceptionClasses; 142 } 143 144 // Fluent API 145 //------------------------------------------------------------------------- 146 /** 147 * The exceptions to catch. 148 * 149 * @param exceptionClasses a list of the exception classes 150 * @return the builder 151 */ 152 public CatchDefinition exceptionClasses(List<Class<? extends Throwable>> exceptionClasses) { 153 setExceptionClasses(exceptionClasses); 154 return this; 155 } 156 157 /** 158 * The exception(s) to catch. 159 * 160 * @param exceptions one or more exceptions 161 * @return the builder 162 */ 163 public CatchDefinition exception(Class<? extends Throwable>... exceptions) { 164 if (exceptionClasses == null) { 165 exceptionClasses = new ArrayList<>(); 166 } 167 if (exceptions != null) { 168 for (Class<? extends Throwable> exception : exceptions) { 169 exceptionClasses.add(exception); 170 } 171 } 172 return this; 173 } 174 175 /** 176 * Sets an additional predicate that should be true before the onCatch is triggered. 177 * <p/> 178 * To be used for fine grained controlling whether a thrown exception should be intercepted 179 * by this exception type or not. 180 * 181 * @param predicate predicate that determines true or false 182 * @return the builder 183 */ 184 public CatchDefinition onWhen(@AsPredicate Predicate predicate) { 185 setOnWhen(new WhenDefinition(predicate)); 186 return this; 187 } 188 189 /** 190 * Sets whether the exchange should be marked as handled or not. 191 * 192 * @param handled handled or not 193 * @return the builder 194 * @deprecated will be removed in Camel 3.0. Instead of using handled(false) you can re-throw the exception 195 * from a {@link Processor} or use the {@link ProcessorDefinition#throwException(Exception)} 196 */ 197 @Deprecated 198 public CatchDefinition handled(boolean handled) { 199 Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(handled)); 200 return handled(expression); 201 } 202 203 /** 204 * Sets whether the exchange should be marked as handled or not. 205 * 206 * @param handled predicate that determines true or false 207 * @return the builder 208 * @deprecated will be removed in Camel 3.0. Instead of using handled(false) you can re-throw the exception 209 * from a {@link Processor} or use the {@link ProcessorDefinition#throwException(Exception)} 210 */ 211 @Deprecated 212 public CatchDefinition handled(@AsPredicate Predicate handled) { 213 setHandledPolicy(handled); 214 return this; 215 } 216 217 /** 218 * Sets whether the exchange should be marked as handled or not. 219 * 220 * @param handled expression that determines true or false 221 * @return the builder 222 * @deprecated will be removed in Camel 3.0. Instead of using handled(false) you can re-throw the exception 223 * from a {@link Processor} or use the {@link ProcessorDefinition#throwException(Exception)} 224 */ 225 @Deprecated 226 public CatchDefinition handled(@AsPredicate Expression handled) { 227 setHandledPolicy(ExpressionToPredicateAdapter.toPredicate(handled)); 228 return this; 229 } 230 231 /** 232 * Sets the exception class that the CatchType want to catch 233 * 234 * @param exception the exception of class 235 * @return the builder 236 */ 237 public CatchDefinition exceptionClasses(Class<? extends Throwable> exception) { 238 List<Class<? extends Throwable>> list = getExceptionClasses(); 239 list.add(exception); 240 return this; 241 } 242 243 public List<String> getExceptions() { 244 return exceptions; 245 } 246 247 public void setExceptions(List<String> exceptions) { 248 this.exceptions = exceptions; 249 } 250 251 public WhenDefinition getOnWhen() { 252 return onWhen; 253 } 254 255 public void setOnWhen(WhenDefinition onWhen) { 256 this.onWhen = onWhen; 257 } 258 259 public Predicate getHandledPolicy() { 260 return handledPolicy; 261 } 262 263 public void setHandledPolicy(Predicate handledPolicy) { 264 this.handledPolicy = handledPolicy; 265 } 266 267 public ExpressionSubElementDefinition getHandled() { 268 return handled; 269 } 270 271 /** 272 * Expression to be used for evaluate whether the doCatch should catch the exception or not. 273 * 274 * @deprecated not in use 275 */ 276 @Deprecated 277 public void setHandled(ExpressionSubElementDefinition handled) { 278 this.handled = handled; 279 } 280 281 protected List<Class<? extends Throwable>> createExceptionClasses(CamelContext context) throws ClassNotFoundException { 282 // must use the class resolver from CamelContext to load classes to ensure it can 283 // be loaded in all kind of environments such as JEE servers and OSGi etc. 284 List<String> list = getExceptions(); 285 List<Class<? extends Throwable>> answer = new ArrayList<>(list.size()); 286 for (String name : list) { 287 Class<Throwable> type = context.getClassResolver().resolveMandatoryClass(name, Throwable.class); 288 answer.add(type); 289 } 290 return answer; 291 } 292}