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.processor; 018 019import java.util.ArrayList; 020import java.util.Iterator; 021import java.util.List; 022 023import org.apache.camel.AsyncCallback; 024import org.apache.camel.AsyncProcessor; 025import org.apache.camel.Exchange; 026import org.apache.camel.Navigate; 027import org.apache.camel.Processor; 028import org.apache.camel.Traceable; 029import org.apache.camel.spi.IdAware; 030import org.apache.camel.support.ServiceSupport; 031import org.apache.camel.util.AsyncProcessorConverterHelper; 032import org.apache.camel.util.AsyncProcessorHelper; 033import org.apache.camel.util.ExchangeHelper; 034import org.apache.camel.util.ServiceHelper; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038/** 039 * Implements try/catch/finally type processing 040 * 041 * @version 042 */ 043public class TryProcessor extends ServiceSupport implements AsyncProcessor, Navigate<Processor>, Traceable, IdAware { 044 private static final Logger LOG = LoggerFactory.getLogger(TryProcessor.class); 045 046 protected String id; 047 protected final Processor tryProcessor; 048 protected final List<Processor> catchClauses; 049 protected final Processor finallyProcessor; 050 051 public TryProcessor(Processor tryProcessor, List<Processor> catchClauses, Processor finallyProcessor) { 052 this.tryProcessor = tryProcessor; 053 this.catchClauses = catchClauses; 054 this.finallyProcessor = finallyProcessor; 055 } 056 057 public String toString() { 058 String catchText = catchClauses == null || catchClauses.isEmpty() ? "" : " Catches {" + catchClauses + "}"; 059 String finallyText = (finallyProcessor == null) ? "" : " Finally {" + finallyProcessor + "}"; 060 return "Try {" + tryProcessor + "}" + catchText + finallyText; 061 } 062 063 public String getTraceLabel() { 064 return "doTry"; 065 } 066 067 public void process(Exchange exchange) throws Exception { 068 AsyncProcessorHelper.process(this, exchange); 069 } 070 071 public boolean process(Exchange exchange, AsyncCallback callback) { 072 Iterator<Processor> processors = next().iterator(); 073 074 Object lastHandled = exchange.getProperty(Exchange.EXCEPTION_HANDLED); 075 exchange.setProperty(Exchange.EXCEPTION_HANDLED, null); 076 077 while (continueRouting(processors, exchange)) { 078 exchange.setProperty(Exchange.TRY_ROUTE_BLOCK, true); 079 ExchangeHelper.prepareOutToIn(exchange); 080 081 // process the next processor 082 Processor processor = processors.next(); 083 AsyncProcessor async = AsyncProcessorConverterHelper.convert(processor); 084 boolean sync = process(exchange, callback, processors, async, lastHandled); 085 086 // continue as long its being processed synchronously 087 if (!sync) { 088 LOG.trace("Processing exchangeId: {} is continued being processed asynchronously", exchange.getExchangeId()); 089 // the remainder of the try .. catch .. finally will be completed async 090 // so we break out now, then the callback will be invoked which then continue routing from where we left here 091 return false; 092 } 093 094 LOG.trace("Processing exchangeId: {} is continued being processed synchronously", exchange.getExchangeId()); 095 } 096 097 ExchangeHelper.prepareOutToIn(exchange); 098 exchange.removeProperty(Exchange.TRY_ROUTE_BLOCK); 099 exchange.setProperty(Exchange.EXCEPTION_HANDLED, lastHandled); 100 LOG.trace("Processing complete for exchangeId: {} >>> {}", exchange.getExchangeId(), exchange); 101 callback.done(true); 102 return true; 103 } 104 105 protected boolean process(final Exchange exchange, final AsyncCallback callback, 106 final Iterator<Processor> processors, final AsyncProcessor processor, 107 final Object lastHandled) { 108 // this does the actual processing so log at trace level 109 LOG.trace("Processing exchangeId: {} >>> {}", exchange.getExchangeId(), exchange); 110 111 // implement asynchronous routing logic in callback so we can have the callback being 112 // triggered and then continue routing where we left 113 boolean sync = processor.process(exchange, new AsyncCallback() { 114 public void done(boolean doneSync) { 115 // we only have to handle async completion of the pipeline 116 if (doneSync) { 117 return; 118 } 119 120 // continue processing the try .. catch .. finally asynchronously 121 while (continueRouting(processors, exchange)) { 122 exchange.setProperty(Exchange.TRY_ROUTE_BLOCK, true); 123 ExchangeHelper.prepareOutToIn(exchange); 124 125 // process the next processor 126 AsyncProcessor processor = AsyncProcessorConverterHelper.convert(processors.next()); 127 doneSync = process(exchange, callback, processors, processor, lastHandled); 128 129 if (!doneSync) { 130 LOG.trace("Processing exchangeId: {} is continued being processed asynchronously", exchange.getExchangeId()); 131 // the remainder of the try .. catch .. finally will be completed async 132 // so we break out now, then the callback will be invoked which then continue routing from where we left here 133 return; 134 } 135 } 136 137 ExchangeHelper.prepareOutToIn(exchange); 138 exchange.removeProperty(Exchange.TRY_ROUTE_BLOCK); 139 exchange.setProperty(Exchange.EXCEPTION_HANDLED, lastHandled); 140 LOG.trace("Processing complete for exchangeId: {} >>> {}", exchange.getExchangeId(), exchange); 141 callback.done(false); 142 } 143 }); 144 145 return sync; 146 } 147 148 protected boolean continueRouting(Iterator<Processor> it, Exchange exchange) { 149 Object stop = exchange.getProperty(Exchange.ROUTE_STOP); 150 if (stop != null) { 151 boolean doStop = exchange.getContext().getTypeConverter().convertTo(Boolean.class, stop); 152 if (doStop) { 153 LOG.debug("Exchange is marked to stop routing: {}", exchange); 154 return false; 155 } 156 } 157 158 // continue if there are more processors to route 159 return it.hasNext(); 160 } 161 162 protected void doStart() throws Exception { 163 ServiceHelper.startServices(tryProcessor, catchClauses, finallyProcessor); 164 } 165 166 protected void doStop() throws Exception { 167 ServiceHelper.stopServices(tryProcessor, catchClauses, finallyProcessor); 168 } 169 170 public List<Processor> next() { 171 if (!hasNext()) { 172 return null; 173 } 174 List<Processor> answer = new ArrayList<>(); 175 if (tryProcessor != null) { 176 answer.add(tryProcessor); 177 } 178 if (catchClauses != null) { 179 answer.addAll(catchClauses); 180 } 181 if (finallyProcessor != null) { 182 answer.add(finallyProcessor); 183 } 184 return answer; 185 } 186 187 public boolean hasNext() { 188 return tryProcessor != null || catchClauses != null && !catchClauses.isEmpty() || finallyProcessor != null; 189 } 190 191 public String getId() { 192 return id; 193 } 194 195 public void setId(String id) { 196 this.id = id; 197 } 198}