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.processor;
018
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import org.apache.camel.Exchange;
023 import org.apache.camel.Navigate;
024 import org.apache.camel.Processor;
025 import org.apache.camel.impl.ServiceSupport;
026 import org.apache.camel.util.ExchangeHelper;
027 import org.apache.camel.util.ServiceHelper;
028 import org.apache.commons.logging.Log;
029 import org.apache.commons.logging.LogFactory;
030
031 /**
032 * Implements try/catch/finally type processing
033 *
034 * @version $Revision: 881175 $
035 */
036 public class TryProcessor extends ServiceSupport implements Processor, Navigate<Processor>, Traceable {
037 private static final transient Log LOG = LogFactory.getLog(TryProcessor.class);
038
039 protected final Processor tryProcessor;
040 protected final List<CatchProcessor> catchClauses;
041 protected final Processor finallyProcessor;
042
043 public TryProcessor(Processor tryProcessor, List<CatchProcessor> catchClauses, Processor finallyProcessor) {
044 this.tryProcessor = tryProcessor;
045 this.catchClauses = catchClauses;
046 this.finallyProcessor = finallyProcessor;
047 }
048
049 public String toString() {
050 String finallyText = (finallyProcessor == null) ? "" : " Finally {" + finallyProcessor + "}";
051 return "Try {" + tryProcessor + "} " + (catchClauses != null ? catchClauses : "") + finallyText;
052 }
053
054 public String getTraceLabel() {
055 return "doTry";
056 }
057
058 public void process(Exchange exchange) throws Exception {
059 Exception e;
060
061 // try processor first
062 try {
063 tryProcessor.process(exchange);
064 e = exchange.getException();
065
066 // Ignore it if it was handled by the dead letter channel.
067 if (e != null && ExchangeHelper.isFailureHandled(exchange)) {
068 e = null;
069 }
070 } catch (Exception ex) {
071 e = ex;
072 exchange.setException(e);
073 }
074
075 // handle any exception occurred during the try processor
076 try {
077 if (e != null) {
078 handleException(exchange, e);
079 }
080 } finally {
081 // and run finally
082 // notice its always executed since we always enter the try block
083 processFinally(exchange);
084 }
085 }
086
087 protected void doStart() throws Exception {
088 ServiceHelper.startServices(tryProcessor, catchClauses, finallyProcessor);
089 }
090
091 protected void doStop() throws Exception {
092 ServiceHelper.stopServices(finallyProcessor, catchClauses, tryProcessor);
093 }
094
095 protected void handleException(Exchange exchange, Throwable e) throws Exception {
096 if (catchClauses == null) {
097 return;
098 }
099
100 for (CatchProcessor catchClause : catchClauses) {
101 Throwable caught = catchClause.catches(exchange, e);
102 if (caught != null) {
103 if (LOG.isTraceEnabled()) {
104 LOG.trace("This TryProcessor catches the exception: " + caught.getClass().getName() + " caused by: " + e.getMessage());
105 }
106
107 // give the rest of the pipeline another chance
108 exchange.setProperty(Exchange.EXCEPTION_CAUGHT, caught);
109 exchange.setException(null);
110
111 // do not catch any exception here, let it propagate up
112 catchClause.process(exchange);
113
114 // is the exception handled by the catch clause
115 boolean handled = catchClause.handles(exchange);
116
117 if (LOG.isDebugEnabled()) {
118 LOG.debug("The exception is handled: " + handled + " for the exception: " + e.getClass().getName()
119 + " caused by: " + caught.getMessage());
120 }
121
122 if (!handled) {
123 // put exception back as it was not handled
124 if (exchange.getException() == null) {
125 exchange.setException(exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class));
126 }
127 }
128
129 return;
130 }
131 }
132
133 if (LOG.isTraceEnabled()) {
134 LOG.trace("This TryProcessor does not catch the exception: " + e.getClass().getName() + " caused by: " + e.getMessage());
135 }
136 }
137
138 protected void processFinally(Exchange exchange) throws Exception {
139 if (finallyProcessor != null) {
140 Exception lastException = exchange.getException();
141 exchange.setException(null);
142
143 // do not catch any exception here, let it propagate up
144 finallyProcessor.process(exchange);
145 if (exchange.getException() == null) {
146 exchange.setException(lastException);
147 }
148 }
149 }
150
151 public List<Processor> next() {
152 if (!hasNext()) {
153 return null;
154 }
155 List<Processor> answer = new ArrayList<Processor>();
156 if (tryProcessor != null) {
157 answer.add(tryProcessor);
158 }
159 if (catchClauses != null) {
160 answer.addAll(catchClauses);
161 }
162 if (finallyProcessor != null) {
163 answer.add(finallyProcessor);
164 }
165 return answer;
166 }
167
168 public boolean hasNext() {
169 return tryProcessor != null;
170 }
171 }