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 org.apache.camel.AsyncCallback;
020import org.apache.camel.Exchange;
021import org.apache.camel.Processor;
022import org.apache.camel.Traceable;
023import org.apache.camel.spi.IdAware;
024import org.apache.camel.util.ExchangeHelper;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027
028/**
029 * Processor to handle do finally supporting asynchronous routing engine
030 *
031 * @version
032 */
033public class FinallyProcessor extends DelegateAsyncProcessor implements Traceable, IdAware {
034
035    private static final Logger LOG = LoggerFactory.getLogger(FinallyProcessor.class);
036    private String id;
037
038    public FinallyProcessor(Processor processor) {
039        super(processor);
040    }
041
042    @Override
043    public boolean process(final Exchange exchange, final AsyncCallback callback) {
044        // clear exception and fault so finally block can be executed
045        final boolean fault;
046        if (exchange.hasOut()) {
047            fault = exchange.getOut().isFault();
048            exchange.getOut().setFault(false);
049        } else {
050            fault = exchange.getIn().isFault();
051            exchange.getIn().setFault(false);
052        }
053
054        final Exception exception = exchange.getException();
055        exchange.setException(null);
056        // but store the caught exception as a property
057        if (exception != null) {
058            exchange.setProperty(Exchange.EXCEPTION_CAUGHT, exception);
059        }
060
061        // store the last to endpoint as the failure endpoint
062        if (exchange.getProperty(Exchange.FAILURE_ENDPOINT) == null) {
063            exchange.setProperty(Exchange.FAILURE_ENDPOINT, exchange.getProperty(Exchange.TO_ENDPOINT));
064        }
065
066        // continue processing
067        return processor.process(exchange, new FinallyAsyncCallback(exchange, callback, exception, fault));
068    }
069
070    @Override
071    public String toString() {
072        return "Finally{" + getProcessor() + "}";
073    }
074
075    public String getTraceLabel() {
076        return "finally";
077    }
078
079    public String getId() {
080        return id;
081    }
082
083    public void setId(String id) {
084        this.id = id;
085    }
086
087    private static final class FinallyAsyncCallback implements AsyncCallback {
088
089        private final Exchange exchange;
090        private final AsyncCallback callback;
091        private final Exception exception;
092        private final boolean fault;
093
094        FinallyAsyncCallback(Exchange exchange, AsyncCallback callback, Exception exception, boolean fault) {
095            this.exchange = exchange;
096            this.callback = callback;
097            this.exception = exception;
098            this.fault = fault;
099        }
100
101        @Override
102        public void done(boolean doneSync) {
103            try {
104                if (exception == null) {
105                    exchange.removeProperty(Exchange.FAILURE_ENDPOINT);
106                } else {
107                    // set exception back on exchange
108                    exchange.setException(exception);
109                    exchange.setProperty(Exchange.EXCEPTION_CAUGHT, exception);
110                }
111                // set fault flag back
112                if (fault) {
113                    if (exchange.hasOut()) {
114                        exchange.getOut().setFault(true);
115                    } else {
116                        exchange.getIn().setFault(true);
117                    }
118                }
119
120                if (!doneSync) {
121                    // signal callback to continue routing async
122                    ExchangeHelper.prepareOutToIn(exchange);
123                    LOG.trace("Processing complete for exchangeId: {} >>> {}", exchange.getExchangeId(), exchange);
124                }
125            } finally {
126                // callback must always be called
127                callback.done(doneSync);
128            }
129        }
130
131        @Override
132        public String toString() {
133            return "FinallyAsyncCallback";
134        }
135    }
136
137}