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