Package com.graphaware.runtime.manager

Source Code of com.graphaware.runtime.manager.BaseTxDrivenModuleManager

package com.graphaware.runtime.manager;

import com.graphaware.runtime.metadata.DefaultTxDrivenModuleMetadata;
import com.graphaware.runtime.metadata.ModuleMetadataRepository;
import com.graphaware.runtime.metadata.TxDrivenModuleMetadata;
import com.graphaware.runtime.module.DeliberateTransactionRollbackException;
import com.graphaware.runtime.module.NeedsInitializationException;
import com.graphaware.runtime.module.TxDrivenModule;
import com.graphaware.tx.event.improved.api.FilteredTransactionData;
import com.graphaware.tx.event.improved.data.TransactionDataContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
* {@link BaseModuleManager} for {@link TxDrivenModule}s.
*/
public abstract class BaseTxDrivenModuleManager<T extends TxDrivenModule> extends BaseModuleManager<TxDrivenModuleMetadata, T> implements TxDrivenModuleManager<T> {

    private static final Logger LOG = LoggerFactory.getLogger(BaseTxDrivenModuleManager.class);

    /**
     * Construct a new manager.
     *
     * @param metadataRepository repository for storing module metadata.
     */
    protected BaseTxDrivenModuleManager(ModuleMetadataRepository metadataRepository) {
        super(metadataRepository);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void handleCorruptMetadata(T module) {
        LOG.info("Module " + module.getId() + " seems to have corrupted metadata, will re-initialize...");
        reinitialize(module);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void handleNoMetadata(T module) {
        LOG.info("Module " + module.getId() + " seems to have been registered for the first time, will initialize...");
        initialize(module);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected TxDrivenModuleMetadata createFreshMetadata(T module) {
        return new DefaultTxDrivenModuleMetadata(module.getConfiguration());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected TxDrivenModuleMetadata acknowledgeMetadata(T module, TxDrivenModuleMetadata metadata) {
        if (metadata.needsInitialization()) {
            LOG.info("Module " + module.getId() + " has been marked for re-initialization on " + new Date(metadata.problemTimestamp()).toString() + ". Will re-initialize...");
            reinitialize(module);
            return createFreshMetadata(module);
        }

        if (!metadata.getConfig().equals(module.getConfiguration())) {
            LOG.info("Module " + module.getId() + " seems to have changed configuration since last run, will re-initialize...");
            reinitialize(module);
            return createFreshMetadata(module);
        }

        LOG.info("Module " + module.getId() + " has not changed configuration since last run, already initialized.");
        return metadata;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void startModules() {
        LOG.info("Starting transaction-driven modules...");
        for (T module : modules.values()) {
            start(module);
        }
        LOG.info("Transaction-driven modules started.");
    }

    /**
     * Start module. This means preparing for doing the actual work. Call in a single-thread exactly once on each module
     * every time the runtime starts.
     *
     * @param module to be started.
     */
    protected abstract void start(T module);

    /**
     * Initialize module. This means doing any work necessary for a module that has been registered for the first time
     * on an existing database, or that has been previously registered with different configuration.
     * <p/>
     * For example, a module that performs some in-graph caching needs to write information into the graph so that when
     * the method returns, the graph is in the same state as it would be if the module has been running all the time
     * since the graph was empty.
     * <p/>
     * Note that for many modules, it might not be necessary to do anything.
     *
     * @param module to initialize.
     */
    protected abstract void initialize(T module);

    /**
     * Re-initialize module. This means cleaning up all data this module might have ever written to the graph and
     * doing any work necessary for a module that has been registered for the first time
     * on an existing database, or that has been previously registered with different configuration.
     * <p/>
     * For example, a module that performs some in-graph caching needs to write information into the graph so that when
     * the method returns, the graph is in the same state as it would be if the module has been running all the time
     * since the graph was empty.
     * <p/>
     * Note that for many modules, it might not be necessary to do anything.
     *
     * @param module to initialize.
     */
    protected abstract void reinitialize(T module);

    /**
     * {@inheritDoc}
     */
    @Override
    public Map<String, Object> beforeCommit(TransactionDataContainer transactionData) {
        Map<String, Object> result = new HashMap<>();

        for (T module : modules.values()) {
            FilteredTransactionData filteredTransactionData = new FilteredTransactionData(transactionData, module.getConfiguration().getInclusionPolicies());

            if (!filteredTransactionData.mutationsOccurred()) {
                continue;
            }

            Object state = null;

            try {
                state = module.beforeCommit(filteredTransactionData);
            } catch (NeedsInitializationException e) {
                LOG.warn("Module " + module.getId() + " seems to have a problem and will be re-initialized next time the database is started. ");
                TxDrivenModuleMetadata moduleMetadata = metadataRepository.getModuleMetadata(module);
                metadataRepository.persistModuleMetadata(module, moduleMetadata.markedNeedingInitialization());
            } catch (DeliberateTransactionRollbackException e) {
                LOG.debug("Module " + module.getId() + " threw an exception indicating that the transaction should be rolled back.", e);

                result.put(module.getId(), state);      //just so the module gets afterRollback called as well
                afterRollback(result); //remove this when https://github.com/neo4j/neo4j/issues/2660 is resolved

                throw e;               //will cause rollback
            } catch (RuntimeException e) {
                LOG.warn("Module " + module.getId() + " threw an exception", e);
            }

            result.put(module.getId(), state);
        }

        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void afterCommit(Map<String, Object> states) {
        for (T module : modules.values()) {
            if (!states.containsKey(module.getId())) {
                return; //perhaps module wasn't interested, or threw RuntimeException
            }

            module.afterCommit(states.get(module.getId()));
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void afterRollback(Map<String, Object> states) {
        for (T module : modules.values()) {
            if (!states.containsKey(module.getId())) {
                return; //rollback happened before this module had a go
            }

            module.afterRollback(states.get(module.getId()));
        }
    }
}
TOP

Related Classes of com.graphaware.runtime.manager.BaseTxDrivenModuleManager

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.