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 // do catch does not mandate a child processor 099 Processor childProcessor = this.createChildProcessor(routeContext, false); 100 101 Predicate when = null; 102 if (onWhen != null) { 103 when = onWhen.getExpression().createPredicate(routeContext); 104 } 105 106 Predicate handle = handledPolicy; 107 if (handled != null) { 108 handle = handled.createPredicate(routeContext); 109 } 110 111 return new CatchProcessor(exceptionClasses, childProcessor, when, handle); 112 } 113 114 @Override 115 public List<ProcessorDefinition<?>> getOutputs() { 116 return outputs; 117 } 118 119 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 120 this.outputs = outputs; 121 } 122 123 public boolean isOutputSupported() { 124 return true; 125 } 126 127 public List<Class<? extends Throwable>> getExceptionClasses() { 128 return exceptionClasses; 129 } 130 131 public void setExceptionClasses(List<Class<? extends Throwable>> exceptionClasses) { 132 this.exceptionClasses = exceptionClasses; 133 } 134 135 // Fluent API 136 //------------------------------------------------------------------------- 137 /** 138 * Sets the exceptionClasses of the CatchType 139 * 140 * @param exceptionClasses a list of the exception classes 141 * @return the builder 142 */ 143 public CatchDefinition exceptionClasses(List<Class<? extends Throwable>> exceptionClasses) { 144 setExceptionClasses(exceptionClasses); 145 return this; 146 } 147 148 /** 149 * Sets an additional predicate that should be true before the onCatch is triggered. 150 * <p/> 151 * To be used for fine grained controlling whether a thrown exception should be intercepted 152 * by this exception type or not. 153 * 154 * @param predicate predicate that determines true or false 155 * @return the builder 156 */ 157 public CatchDefinition onWhen(Predicate predicate) { 158 setOnWhen(new WhenDefinition(predicate)); 159 return this; 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 * @deprecated will be removed in Camel 3.0. Instead of using handled(false) you can re-throw the exception 168 * from a {@link Processor} or use the {@link ProcessorDefinition#throwException(Exception)} 169 */ 170 @Deprecated 171 public CatchDefinition handled(boolean handled) { 172 Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(handled)); 173 return handled(expression); 174 } 175 176 /** 177 * Sets whether the exchange should be marked as handled or not. 178 * 179 * @param handled predicate that determines true or false 180 * @return the builder 181 * @deprecated will be removed in Camel 3.0. Instead of using handled(false) you can re-throw the exception 182 * from a {@link Processor} or use the {@link ProcessorDefinition#throwException(Exception)} 183 */ 184 @Deprecated 185 public CatchDefinition handled(Predicate handled) { 186 setHandledPolicy(handled); 187 return this; 188 } 189 190 /** 191 * Sets whether the exchange should be marked as handled or not. 192 * 193 * @param handled expression that determines true or false 194 * @return the builder 195 * @deprecated will be removed in Camel 3.0. Instead of using handled(false) you can re-throw the exception 196 * from a {@link Processor} or use the {@link ProcessorDefinition#throwException(Exception)} 197 */ 198 @Deprecated 199 public CatchDefinition handled(Expression handled) { 200 setHandledPolicy(ExpressionToPredicateAdapter.toPredicate(handled)); 201 return this; 202 } 203 204 /** 205 * Sets the exception class that the CatchType want to catch 206 * 207 * @param exception the exception of class 208 * @return the builder 209 */ 210 public CatchDefinition exceptionClasses(Class<? extends Throwable> exception) { 211 List<Class<? extends Throwable>> list = getExceptionClasses(); 212 list.add(exception); 213 return this; 214 } 215 216 public List<String> getExceptions() { 217 return exceptions; 218 } 219 220 public void setExceptions(List<String> exceptions) { 221 this.exceptions = exceptions; 222 } 223 224 public WhenDefinition getOnWhen() { 225 return onWhen; 226 } 227 228 public void setOnWhen(WhenDefinition onWhen) { 229 this.onWhen = onWhen; 230 } 231 232 public Predicate getHandledPolicy() { 233 return handledPolicy; 234 } 235 236 public void setHandledPolicy(Predicate handledPolicy) { 237 this.handledPolicy = handledPolicy; 238 } 239 240 public ExpressionSubElementDefinition getHandled() { 241 return handled; 242 } 243 244 public void setHandled(ExpressionSubElementDefinition handled) { 245 this.handled = handled; 246 } 247 248 protected List<Class<? extends Throwable>> createExceptionClasses(CamelContext context) throws ClassNotFoundException { 249 // must use the class resolver from CamelContext to load classes to ensure it can 250 // be loaded in all kind of environments such as JEE servers and OSGi etc. 251 List<String> list = getExceptions(); 252 List<Class<? extends Throwable>> answer = new ArrayList<Class<? extends Throwable>>(list.size()); 253 for (String name : list) { 254 Class<Throwable> type = context.getClassResolver().resolveMandatoryClass(name, Throwable.class); 255 answer.add(type); 256 } 257 return answer; 258 } 259 }