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.Arrays; 021import java.util.Iterator; 022import java.util.List; 023 024import javax.xml.bind.annotation.XmlAccessType; 025import javax.xml.bind.annotation.XmlAccessorType; 026import javax.xml.bind.annotation.XmlRootElement; 027import javax.xml.bind.annotation.XmlTransient; 028 029import org.apache.camel.Predicate; 030import org.apache.camel.spi.AsPredicate; 031import org.apache.camel.spi.Metadata; 032 033/** 034 * Marks the beginning of a try, catch, finally block 035 */ 036@Metadata(label = "error") 037@XmlRootElement(name = "doTry") 038@XmlAccessorType(XmlAccessType.FIELD) 039public class TryDefinition extends OutputDefinition<TryDefinition> { 040 @XmlTransient 041 private List<CatchDefinition> catchClauses; 042 @XmlTransient 043 private FinallyDefinition finallyClause; 044 @XmlTransient 045 private boolean initialized; 046 @XmlTransient 047 private List<ProcessorDefinition<?>> outputsWithoutCatches; 048 049 public TryDefinition() { 050 } 051 052 @Override 053 public String toString() { 054 return "DoTry[" + getOutputs() + "]"; 055 } 056 057 @Override 058 public String getShortName() { 059 return "doTry"; 060 } 061 062 @Override 063 public String getLabel() { 064 return "doTry"; 065 } 066 067 // Fluent API 068 // ------------------------------------------------------------------------- 069 070 /** 071 * Handles the given exception 072 * 073 * @param exceptionType the exception 074 * @return the try builder 075 */ 076 @SuppressWarnings("unchecked") 077 public TryDefinition doCatch(Class<? extends Throwable> exceptionType) { 078 // this method is introduced to avoid compiler warnings about the 079 // generic Class arrays in the case we've got only one single Class 080 // to build a TryDefinition for 081 return doCatch(new Class[] {exceptionType}); 082 } 083 084 /** 085 * Handles the given exception(s) 086 * 087 * @param exceptionType the exception(s) 088 * @return the try builder 089 */ 090 public TryDefinition doCatch(Class<? extends Throwable>... exceptionType) { 091 popBlock(); 092 List<Class<? extends Throwable>> list = Arrays.asList(exceptionType); 093 CatchDefinition answer = new CatchDefinition(list); 094 addOutput(answer); 095 pushBlock(answer); 096 return this; 097 } 098 099 /** 100 * The finally block for a given handle 101 * 102 * @return the try builder 103 */ 104 public TryDefinition doFinally() { 105 popBlock(); 106 FinallyDefinition answer = new FinallyDefinition(); 107 addOutput(answer); 108 pushBlock(answer); 109 return this; 110 } 111 112 /** 113 * Sets an additional predicate that should be true before the onCatch is 114 * triggered. 115 * <p/> 116 * To be used for fine grained controlling whether a thrown exception should 117 * be intercepted by this exception type or not. 118 * 119 * @param predicate predicate that determines true or false 120 * @return the builder 121 */ 122 public TryDefinition onWhen(@AsPredicate Predicate predicate) { 123 // we must use a delegate so we can use the fluent builder based on 124 // TryDefinition 125 // to configure all with try .. catch .. finally 126 // set the onWhen predicate on all the catch definitions 127 Iterator<CatchDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(getOutputs(), CatchDefinition.class); 128 while (it.hasNext()) { 129 CatchDefinition doCatch = it.next(); 130 doCatch.setOnWhen(new WhenDefinition(predicate)); 131 } 132 return this; 133 } 134 135 // Properties 136 // ------------------------------------------------------------------------- 137 138 public List<CatchDefinition> getCatchClauses() { 139 if (catchClauses == null) { 140 checkInitialized(); 141 } 142 return catchClauses; 143 } 144 145 public FinallyDefinition getFinallyClause() { 146 if (finallyClause == null) { 147 checkInitialized(); 148 } 149 return finallyClause; 150 } 151 152 public List<ProcessorDefinition<?>> getOutputsWithoutCatches() { 153 if (outputsWithoutCatches == null) { 154 checkInitialized(); 155 } 156 return outputsWithoutCatches; 157 } 158 159 @Override 160 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 161 initialized = false; 162 super.setOutputs(outputs); 163 } 164 165 @Override 166 public void addOutput(ProcessorDefinition<?> output) { 167 initialized = false; 168 super.addOutput(output); 169 } 170 171 @Override 172 public void preCreateProcessor() { 173 // force re-creating initialization to ensure its up-to-date 174 initialized = false; 175 checkInitialized(); 176 } 177 178 /** 179 * Checks whether or not this object has been initialized 180 */ 181 protected void checkInitialized() { 182 if (!initialized) { 183 initialized = true; 184 outputsWithoutCatches = new ArrayList<>(); 185 catchClauses = new ArrayList<>(); 186 finallyClause = null; 187 188 for (ProcessorDefinition<?> output : outputs) { 189 if (output instanceof CatchDefinition) { 190 catchClauses.add((CatchDefinition)output); 191 } else if (output instanceof FinallyDefinition) { 192 if (finallyClause != null) { 193 throw new IllegalArgumentException("Multiple finally clauses added: " + finallyClause + " and " + output); 194 } else { 195 finallyClause = (FinallyDefinition)output; 196 } 197 } else { 198 outputsWithoutCatches.add(output); 199 } 200 } 201 } 202 } 203}