All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.petals.camel.component.PetalsCamelConsumer Maven / Gradle / Ivy

There is a newer version: 1.3.0
Show newest version
/**
 * Copyright (c) 2015-2016 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.camel.component;

import java.util.logging.Level;

import javax.jbi.messaging.MessagingException;

import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.impl.DefaultConsumer;
import org.ow2.petals.camel.PetalsCamelRoute;
import org.ow2.petals.camel.PetalsChannel.PetalsProvidesChannel;
import org.ow2.petals.camel.PetalsChannel.SendAsyncCallback;
import org.ow2.petals.camel.component.utils.Conversions;
import org.ow2.petals.commons.log.FlowAttributes;
import org.ow2.petals.commons.log.PetalsExecutionContext;

// TODO should I be suspendable?
public class PetalsCamelConsumer extends DefaultConsumer implements PetalsCamelRoute {

    private final PetalsProvidesChannel provides;

    public PetalsCamelConsumer(final PetalsCamelEndpoint endpoint, final Processor processor) {
        super(endpoint, processor);
        this.provides = endpoint.getComponent().getContext().getProvidesChannel(endpoint.getService());
    }

    @Override
    protected void doStart() throws Exception {
        super.doStart();
        // let's register so that when MEX are received, they will be passed to us
        getEndpoint().getComponent().getContext().registerRoute(getEndpoint().getService(), this);
    }

    @Override
    protected void doStop() throws Exception {
        // we unregister
        getEndpoint().getComponent().getContext().unregisterRoute(getEndpoint().getService());
        super.doStop();
    }

    @Override
    public boolean process(final org.ow2.petals.component.framework.api.message.Exchange exchange) {

        final Exchange camelExchange = getEndpoint().createExchange();
        assert camelExchange != null;

        Conversions.populateNewCamelExchange(exchange, camelExchange);

        if (getEndpoint().isSynchronous()) {
            // in that case, this method won't return until the route is fully executed

            if (this.provides.getLogger().isLoggable(Level.FINE)) {
                this.provides.getLogger().fine("Processing a Camel exchange (with id: " + exchange.getExchangeId()
                        + ") with the route in sync mode");
            }

            try {
                getProcessor().process(camelExchange);
            } catch (final Exception e) {
                this.provides.getLogger().log(Level.SEVERE,
                        "Just set an error on the Petals Exchange " + exchange.getExchangeId(), e);
                exchange.setError(e);
            }

            if (PetalsCamelConsumer.this.provides.getLogger().isLoggable(Level.FINE)) {
                PetalsCamelConsumer.this.provides.getLogger().fine("Handling a Camel exchange (with id: "
                        + exchange.getExchangeId() + ") processed by the route in sync mode ");
            }

            handleAnswer(camelExchange, exchange);
            return true;
        } else {
            if (this.provides.getLogger().isLoggable(Level.FINE)) {
                this.provides.getLogger().fine("Processing a Camel exchange (with id: " + exchange.getExchangeId()
                        + ") with the route in async mode");
            }

            // let's store it for later in case we come back in a different thread
            final FlowAttributes current = PetalsExecutionContext.getFlowAttributes();
            assert current != null;

            return getAsyncProcessor().process(camelExchange, new AsyncCallback() {
                @Override
                public void done(final boolean doneSync) {
                    // no need to use doneSync: if it is true it just means we are being executed synchronously (w.r.t.
                    // the execution of process from this class).

                    // Here, we are not sure if we are in the same thread as before because we went potentially went
                    // through Camel, and we need the context to be filled if possible for the sendAsync to work as best
                    // as possible
                    PetalsExecutionContext.putFlowAttributes(current);

                    if (PetalsCamelConsumer.this.provides.getLogger().isLoggable(Level.FINE)) {
                        PetalsCamelConsumer.this.provides.getLogger()
                                .fine("Handling a Camel exchange (with id: " + exchange.getExchangeId()
                                        + ") processed by the route in async mode "
                                        + (doneSync ? "(but executed in sync mode apparently)" : ""));
                    }

                    handleAnswer(camelExchange, exchange);
                }
            });
        }
    }

    private void handleAnswer(final Exchange camelExchange,
            final org.ow2.petals.component.framework.api.message.Exchange exchange) {

        try {
            Conversions.populateAnswerPetalsExchange(camelExchange, exchange);
        } catch (final MessagingException e) {
            // this must be caught before sending to be sure that if an error happens here it is sent back!
            this.provides.getLogger().log(Level.SEVERE,
                    "Just set an error on the Petals Exchange " + exchange.getExchangeId(), e);
            exchange.setError(e);
        }

        try {
            if (!exchange.isActiveStatus()) {
                this.provides.send(exchange);
            } else {
                // TODO maybe we should render that answer synchronicity configurable... for now let's use sendAsync in
                // order not to tie resources for simple acknowledging (there is no need to block the current execution
                // nor anything)
                // TODO and actually, shouldn't I WAIT for it before letting other continue, or before letting this
                // method to return... which others? maybe not then!
                // TODO for now the timeout is not settable, let's use default provides value (-1) as a starter...
                final boolean wasFault = exchange.getFault() != null;
                final boolean wasOut = exchange.isOutMessage();
                final boolean expectingAnswer = wasFault || wasOut;
                if (getEndpoint().isSynchronous()) {
                    final boolean ok = this.provides.sendSync(exchange, -1L);
                    handleAnswerAnswer(wasOut, expectingAnswer, exchange, !ok);
                } else {
                    this.provides.sendAsync(exchange, -1L, new SendAsyncCallback() {
                        @Override
                        public void done(final org.ow2.petals.component.framework.api.message.Exchange exchange,
                                final boolean timedOut) {
                            handleAnswerAnswer(wasOut, expectingAnswer, exchange, timedOut);
                        }
                    });
                }
            }
        } catch (final MessagingException e) {
            // if the send fails, there is nothing we can do except logging the error
            provides.getLogger().log(Level.SEVERE,
                    "An exchange (" + exchange.getExchangeId() + ") couldn't be sent back", e);
        }
    }

    private void handleAnswerAnswer(final boolean wasOut, final boolean expectingAnswer,
            final org.ow2.petals.component.framework.api.message.Exchange exchange, final boolean timedOut) {
        if (timedOut) {
            provides.getLogger().warning("The exchange I sent back to the NMR never got acknowledged, it timed out: "
                    + exchange.getExchangeId());
        } else {
            provides.getLogger()
                    .fine("Got an answer from my answer I sent to the NMR for exchange " + exchange.getExchangeId());

            if (expectingAnswer && exchange.isDoneStatus()) {
                if (provides.getLogger().isLoggable(Level.FINE)) {
                    provides.getLogger().fine("Correctly received acknowledgment for our previous answer (id: "
                            + exchange.getExchangeId() + ")");
                }
                // TODO that should be transfered back to the original caller!!! see PetalsCamelProducer
            } else if (exchange.isInOptionalOutPattern() && wasOut && exchange.getFault() != null) {
                try {
                    // TODO the fault should be transfered back to the original caller before we
                    // answer!!!
                    exchange.setDoneStatus();
                    PetalsCamelConsumer.this.provides.send(exchange);
                } catch (final MessagingException e) {
                    provides.getLogger().log(Level.SEVERE,
                            "An exchange (" + exchange.getExchangeId() + ") couldn't be sent back", e);
                }
            } else {
                // TODO log nicely for other (invalid) cases...
                provides.getLogger().warning("Unknown situation in MEP for exchange " + exchange.getExchangeId());
            }
            // TODO and add tests for all of this!
        }
    }

    @SuppressWarnings("null")
    @Override
    public PetalsCamelEndpoint getEndpoint() {
        return (PetalsCamelEndpoint) super.getEndpoint();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy