Package com.codebullets.sagalib.processing

Source Code of com.codebullets.sagalib.processing.SagaExecutionTask

/*
* Copyright 2013 Stefan Domnanovits
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.codebullets.sagalib.processing;

import com.codebullets.sagalib.context.ExecutionContext;
import com.codebullets.sagalib.Saga;
import com.codebullets.sagalib.context.NeedContext;
import com.codebullets.sagalib.storage.StateStorage;
import com.codebullets.sagalib.timeout.TimeoutManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Provider;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* Perform execution of saga message handling. This class is the execution
* root unit when handling messages as part of an execution strategy.
*/
public class SagaExecutionTask implements Runnable {
    private static final Logger LOG = LoggerFactory.getLogger(SagaExecutionTask.class);

    private final SagaFactory sagaFactory;
    private final HandlerInvoker invoker;
    private final StateStorage storage;
    private final TimeoutManager timeoutManager;
    private final Object message;
    private final Provider<ExecutionContext> contextProvider;

    /**
     * Generates a new instance of SagaExecutionTask.
     */
    public SagaExecutionTask(final SagaFactory sagaFactory, final HandlerInvoker invoker, final StateStorage storage, final TimeoutManager timeoutManager,
                             final Object message, final Provider<ExecutionContext> contextProvider) {
        this.sagaFactory = sagaFactory;
        this.invoker = invoker;
        this.storage = storage;
        this.timeoutManager = timeoutManager;
        this.message = message;
        this.contextProvider = contextProvider;
    }

    /**
     * Performs synchronous saga handling of the message provided in ctor.
     *
     * @throws InvocationTargetException Thrown when invocation of the handler method fails.
     * @throws IllegalAccessException Thrown when access to the handler method fails.
     */
    public void handle() throws InvocationTargetException, IllegalAccessException {
        checkNotNull(message, "Message to handle must not be null.");
        handleSagaMessage(message);
    }

    /**
     * Perform handling of a single message.
     */
    private void handleSagaMessage(final Object invokeParam) throws InvocationTargetException, IllegalAccessException {
        Collection<SagaInstanceDescription> sagaDescriptions = sagaFactory.create(invokeParam);
        if (sagaDescriptions.isEmpty()) {
            LOG.warn("No saga found to handle message. {}", invokeParam);
        } else {
            ExecutionContext context = contextProvider.get();

            for (SagaInstanceDescription sagaDescription : sagaDescriptions) {
                Saga saga = sagaDescription.getSaga();
                setSagaExecutionContext(saga, context);

                invoker.invoke(saga, invokeParam);
                updateStateStorage(sagaDescription);

                if (context.dispatchingStopped()) {
                    LOG.debug("Handler dispatching stopped after invoking saga {}.", sagaDescription.getSaga().getClass().getSimpleName());
                    break;
                }
            }
        }
    }

    private void setSagaExecutionContext(final Saga saga, final ExecutionContext context) {
        if (saga instanceof NeedContext) {
            ((NeedContext) saga).setExecutionContext(context);
        }
    }

    /**
     * Updates the state storage depending on whether the saga is completed or keeps on running.
     */
    private void updateStateStorage(final SagaInstanceDescription description) {
        Saga saga = description.getSaga();

        // if saga has finished delete existing state and possible timeouts
        // if saga has just been created state has never been save and there
        // is no need to delete it.
        if (saga.isFinished() && !description.isStarting()) {
            storage.delete(saga.state().getSagaId());
            timeoutManager.cancelTimeouts(saga.state().getSagaId());
        } else if (!saga.isFinished()) {
            storage.save(saga.state());
        }
    }

    /**
     * Similar to {@link #handle()} but intended for execution on any thread.<p/>
     * May throw a runtime exception in case something went wrong invoking the target saga message handler.
     */
    @Override
    public void run() {
        try {
            handle();
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
TOP

Related Classes of com.codebullets.sagalib.processing.SagaExecutionTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.