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

com.tangosol.persistence.SafePersistenceWrappers Maven / Gradle / Ivy

There is a newer version: 24.03
Show newest version
/*
 * Copyright (c) 2000, 2021, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.persistence;

import com.oracle.coherence.common.base.Collector;
import com.oracle.coherence.common.base.Continuation;

import com.oracle.coherence.persistence.PersistenceEnvironment;
import com.oracle.coherence.persistence.PersistenceManager;
import com.oracle.coherence.persistence.PersistentStore;

import com.tangosol.util.Base;
import com.tangosol.util.NullImplementation;
import com.tangosol.util.NullImplementation.NullPersistenceEnvironment;
import com.tangosol.util.NullImplementation.NullPersistenceManager;
import com.tangosol.util.NullImplementation.NullPersistentStore;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * SafePersistenceWrappers provides safe wrapper implementations of persistence
 * layer interfaces that can be used to consolidate error handling across the
 * various persistence layers.
 *
 * @since Coherence 12.1.3
 * @author rhl/jh 2013.07.18
 */
public class SafePersistenceWrappers
    {
    // ----- static helpers -------------------------------------------------

    /**
     * Return the underlying (non-"Safe") PersistenceEnvironment.
     *
     * @param env  a PersistenceEnvironment
     * @param   the type of a raw, environment specific object representation
     *
     * @return the underlying PersistenceEnvironment implementation
     */
    public static  PersistenceEnvironment unwrap(PersistenceEnvironment env)
        {
        while (env instanceof SafePersistenceEnvironment)
            {
            env = ((SafePersistenceEnvironment) env).getEnvironment();
            }

        return env;
        }

    /**
     * Return the underlying (non-"Safe") PersistenceManager.
     *
     * @param mgr  a PersistenceManager
     * @param   the type of a raw, environment specific object representation
     *
     * @return the underlying PersistenceManager implementation
     */
    public static  PersistenceManager unwrap(PersistenceManager mgr)
        {
        while (mgr instanceof SafePersistenceManager)
            {
            mgr = ((SafePersistenceManager) mgr).getManager();
            }

        return mgr;
        }

    /**
     * Return the underlying (non-"Safe") PersistentStore.
     *
     * @param store  a PersistentStore
     * @param     the type of a raw, environment specific object representation
     *
     * @return the underlying PersistentStore implementation
     */
    public static  PersistentStore unwrap(PersistentStore store)
        {
        while (store instanceof SafePersistentStore)
            {
            store = ((SafePersistentStore) store).getStore();
            }

        return store;
        }

    /**
     * Return a simple FailureContinuationFactory that uses the specified failure
     * continuation to handle failures at any layer of the persistence
     * implementation.
     *
     * @param cont  the failure continuation
     * @param    the type of a raw, environment specific object representation
     * @param    the type of a Throwable failure to protect
     *
     * @return a simple FailureContinuationFactory that uses a single common
     *         failure continuation
     */
    protected static  FailureContinuationFactory getSimpleFactory(final Continuation cont)
        {
        return new FailureContinuationFactory()
            {
            public Continuation getEnvironmentContinuation(PersistenceEnvironment env)
                {
                return cont;
                }

            public Continuation getManagerContinuation(PersistenceManager mgr)
                {
                return cont;
                }

            public Continuation getStoreContinuation(PersistentStore store)
                {
                return cont;
                }
            };
        }

    // ----- inner class: SafePersistenceEnvironment ------------------------

    /**
     * SafePersistenceEnvironment is a wrapper PersistenceEnvironment implementation
     * which protects all operations on the underlying environment (and any
     * PersistenceManger or PersistentStore instances opened through this environment)
     * from unexpected failures, delegating the exception handling to a failure
     * {@link Continuation}.
     *
     * @param   the type of a raw, environment specific object representation
     * @param   the type of a Throwable failure to protect
     */
    public static class SafePersistenceEnvironment
            extends NullPersistenceEnvironment
        {
        // ----- constructors -----------------------------------------------

        /**
         * Construct a PersistenceEnvironment backed by the specified environment.
         *
         * @param env  the underlying PersistenceEnvironment
         */
        public SafePersistenceEnvironment(PersistenceEnvironment env)
            {
            this(env, DEFAULT_FACTORY);
            }

        /**
         * Construct a PersistenceEnvironment backed by the specified environment.
         *
         * @param env   the underlying PersistenceEnvironment
         * @param cont  the failure continuation to use to handle unexpected exceptions
         */
        public SafePersistenceEnvironment(PersistenceEnvironment env, Continuation cont)
            {
            this(env, getSimpleFactory(cont));
            }

        /**
         * Construct a PersistenceEnvironment backed by the specified environment.
         *
         * @param env      the underlying PersistenceEnvironment
         * @param factory  the failure continuation factory to use to create handlers
         *                 for unexpected exceptions
         */
        public SafePersistenceEnvironment(PersistenceEnvironment env, FailureContinuationFactory factory)
            {
            f_env         = env;
            f_factoryCont = factory;
            f_contFailure = factory.getEnvironmentContinuation(env);
            }

        // ----- accessors --------------------------------------------------

        /**
         * Return the underlying PersistenceEnvironment.
         *
         * @return the underlying PersistenceEnvironment
         */
        public PersistenceEnvironment getEnvironment()
            {
            return f_env;
            }

        // ----- internal methods -------------------------------------------

        /**
         * Called to handle an unexpected exception.
         *
         * @param t  the Throwable
         */
        protected void onException(T t)
            {
            f_contFailure.proceed(t);
            }

        /**
         * Wrap the specified manager in a SafePersistenceManager implementation.
         *
         * @param mgr  the underlying PersistenceManger
         *
         * @return a "safe" PersistenceManger or null if the specified
         *         manager is null
         */
        protected PersistenceManager wrap(PersistenceManager mgr)
            {
            return mgr == null ? null : new SafePersistenceManager<>(mgr, f_factoryCont);
            }

        // ----- PersistenceEnvironment methods -----------------------------

        /**
         * {@inheritDoc}
         */
        public PersistenceManager openActive()
            {
            try
                {
                return wrap(getEnvironment().openActive());
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return NullImplementation.getPersistenceManager();
            }

        /**
         * {@inheritDoc}
         */
        public PersistenceManager openSnapshot(String sSnapshot)
            {
            try
                {
                return wrap(getEnvironment().openSnapshot(sSnapshot));
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return NullImplementation.getPersistenceManager();
            }

        /**
         * {@inheritDoc}
         */
        public PersistenceManager createSnapshot(String sSnapshot, PersistenceManager manager)
            {
            try
                {
                return wrap(getEnvironment().createSnapshot(sSnapshot, unwrap(manager)));
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return NullImplementation.getPersistenceManager();
            }

        /**
         * {@inheritDoc}
         */
        public boolean removeSnapshot(String sSnapshot)
            {
            try
                {
                return getEnvironment().removeSnapshot(sSnapshot);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.removeSnapshot(sSnapshot);
            }

        /**
         * {@inheritDoc}
         */
        public String[] listSnapshots()
            {
            try
                {
                return getEnvironment().listSnapshots();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.listSnapshots();
            }

        /**
         * {@inheritDoc}
         */
        public void release()
            {
            try
                {
                getEnvironment().release();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        // ----- Object methods ---------------------------------------------

        /**
         * Return a human readable description of this SafePersistenceEnvironment.
         *
         * @return a human readable description
         */
        @Override
        public String toString()
            {
            return "Safe" + String.valueOf(getEnvironment());
            }

        // ----- data members -----------------------------------------------

        /**
         * The underlying PersistenceEnvironment.
         */
        protected final PersistenceEnvironment f_env;

        /**
         * The failure continuation for this environment.
         */
        protected final Continuation f_contFailure;

        /**
         * The FailureContinuationFactory.
         */
        protected final FailureContinuationFactory f_factoryCont;
        }

    // ----- inner class: SafePersistenceManager ----------------------------

    /**
     * SafePersistenceManager is a wrapper PersistenceManager implementation which
     * protects all operations on the underlying manager (and any PersistentStore
     * instances opened by the manager) from unexpected failures, delegating
     * the exception handling to a failure {@link Continuation}.
     *
     * @param   the type of a raw, environment specific object representation
     * @param   the type of a Throwable failure to protect
     */
    public static class SafePersistenceManager
            extends NullPersistenceManager
        {
        // ----- constructors -----------------------------------------------

        /**
         * Construct a SafePersistenceManager backed by the specified manager.
         *
         * @param mgr  the underlying PersistenceManager
         */
        public SafePersistenceManager(PersistenceManager mgr)
            {
            this(mgr, DEFAULT_FACTORY);
            }

        /**
         * Construct a SafePersistenceManager backed by the specified manager.
         *
         * @param mgr   the underlying PersistenceManager
         * @param cont  the failure continuation to use to handle unexpected exceptions
         */
        public SafePersistenceManager(PersistenceManager mgr, Continuation cont)
            {
            this(mgr, getSimpleFactory(cont));
            }

        /**
         * Construct a PersistenceManager backed by the specified manager.
         *
         * @param mgr      the underlying PersistenceManager
         * @param factory  the failure continuation factory to use to create handlers
         *                 for unexpected exceptions
         */
        public SafePersistenceManager(PersistenceManager mgr, FailureContinuationFactory factory)
            {
            f_manager     = mgr;
            f_factoryCont = factory;
            f_contFailure = factory.getManagerContinuation(mgr);
            }

        // ----- accessors --------------------------------------------------

        /**
         * Return the underlying PersistenceManager.
         *
         * @return the underlying PersistenceManager
         */
        public PersistenceManager getManager()
            {
            return f_manager;
            }

        // ----- internal methods -------------------------------------------

        /**
         * Called to handle an unexpected exception.
         *
         * @param t  the Throwable
         */
        public void onException(T t)
            {
            f_contFailure.proceed(t);
            }

        /**
         * Wrap the specified store in a SafePersistentStore implementation.
         *
         * @param store  the underlying PersistentStore
         *
         * @return a "safe" PersistenceManger or null if the specified store
         *         is null
         */
        protected PersistentStore wrap(PersistentStore store)
            {
            return store == null ? null : new SafePersistentStore<>(store, f_factoryCont);
            }

        // ----- PersistenceManager methods ---------------------------------

        /**
         * {@inheritDoc}
         */
        public String getName()
            {
            try
                {
                return getManager().getName();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.getName();
            }

        /**
         * {@inheritDoc}
         */
        public PersistentStore createStore(String sId)
            {
            try
                {
                return wrap(getManager().createStore(sId));
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return null;
            }

        /**
         * {@inheritDoc}
         */
        public PersistentStore open(String sId, PersistentStore store)
            {
            try
                {
                return wrap(getManager().open(sId, store));
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.open(sId, store);
            }

        /**
         * {@inheritDoc}
         */
        public PersistentStore open(String sId, PersistentStore store, Collector collector)
            {
            try
                {
                return wrap(getManager().open(sId, store, collector));
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.open(sId, store);
            }

        /**
         * {@inheritDoc}
         */
        public void close(String sId)
            {
            try
                {
                getManager().close(sId);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        /**
         * {@inheritDoc}
         */
        public boolean delete(String sId, boolean fSafe)
            {
            try
                {
                return getManager().delete(sId, fSafe);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.delete(sId, fSafe);
            }

        /**
         * {@inheritDoc}
         */
        public String[] list()
            {
            try
                {
                return getManager().list();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.list();
            }

        /**
         * {@inheritDoc}
         */
        public String[] listOpen()
            {
            try
                {
                return getManager().listOpen();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.listOpen();
            }

        /**
         * {@inheritDoc}
         */
        public void read(String sId, InputStream in)
                throws IOException
            {
            try
                {
                getManager().read(sId, in);
                }
            catch (IOException e)
                {
                throw e;
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        /**
         * {@inheritDoc}
         */
        public void write(String sId, OutputStream out)
                throws IOException
            {
            try
                {
                getManager().write(sId, out);
                }
            catch (IOException e)
                {
                throw e;
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        /**
         * {@inheritDoc}
         */
        public void writeSafe(String sId)
            {
            try
                {
                getManager().writeSafe(sId);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        /**
         * {@inheritDoc}
         */
        public void release()
            {
            try
                {
                getManager().release();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        // ----- Object methods ---------------------------------------------

        /**
         * Return a human readable description of this SafePersistenceManager.
         *
         * @return a human readable description
         */
        @Override
        public String toString()
            {
            return "Safe" + String.valueOf(getManager());
            }

        // ----- data members -----------------------------------------------

        /**
         * The underlying PersistenceManager.
         */
        protected final PersistenceManager f_manager;

        /**
         * The failure continuation for this manager.
         */
        protected final Continuation f_contFailure;

        /**
         * The FailureContinuationFactory.
         */
        protected final FailureContinuationFactory f_factoryCont;
        }

    // ----- inner class: SafePersistentStore -------------------------------

    /**
     * SafePersistentStore is a wrapper PersistentStore implementation which
     * protects all synchronous operations on the underlying store from
     * unexpected failures, delegating the exception handling to a failure
     * {@link Continuation}.  The handling of failures encountered during
     * asynchronous processing remains the responsibility of the {@link Collector}
     * used to open the asynchronous transaction.
     */
    public static class SafePersistentStore
            extends NullPersistentStore
        {
        // ----- constructors -----------------------------------------------

        /**
         * Construct a SafePersistentStore backed by the specified store.
         *
         * @param store  the PersistentStore to protect against exceptions
         */
        public SafePersistentStore(PersistentStore store)
            {
            this(store, DEFAULT_FACTORY);
            }

        /**
         * Construct a SafePersistentStore backed by the specified store.
         *
         * @param store  the underlying PersistentStore
         * @param cont   the failure continuation to use to handle unexpected exceptions
         */
        public SafePersistentStore(PersistentStore store, Continuation cont)
            {
            this(store, getSimpleFactory(cont));
            }

        /**
         * Construct a PersistenceManager backed by the specified manager.
         *
         * @param store    the underlying PersistentStore
         * @param factory  the failure continuation factory to use to create handlers
         *                 for unexpected exceptions
         */
        public SafePersistentStore(PersistentStore store, FailureContinuationFactory factory)
            {
            f_store       = store;
            f_contFailure = factory.getStoreContinuation(store);
            }

        // ----- accessors --------------------------------------------------

        /**
         * Return the underlying PersistentStore.
         *
         * @return the underlying PersistentStore
         */
        public PersistentStore getStore()
            {
            return f_store;
            }

        // ----- internal methods -------------------------------------------

        /**
         * Called to handle an unexpected exception.
         *
         * @param t  the Throwable
         */
        public void onException(T t)
            {
            f_contFailure.proceed(t);
            }

        // ----- PersistentStore methods ------------------------------------

        /**
         * {@inheritDoc}
         */
        public String getId()
            {
            try
                {
                return getStore().getId();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.getId();
            }

        /**
         * {@inheritDoc}
         */
        public boolean ensureExtent(long lExtentId)
            {
            try
                {
                return getStore().ensureExtent(lExtentId);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.ensureExtent(lExtentId);
            }

        /**
         * {@inheritDoc}
         */
        public void deleteExtent(long lExtentId)
            {
            try
                {
                getStore().deleteExtent(lExtentId);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        /**
         * {@inheritDoc}
         */
        public void moveExtent(long lOldExtentId, long lNewExtentId)
            {
            try
                {
                getStore().moveExtent(lOldExtentId, lNewExtentId);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        /**
         * {@inheritDoc}
         */
        public void truncateExtent(long lExtentId)
            {
            try
                {
                getStore().truncateExtent(lExtentId);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        /**
         * {@inheritDoc}
         */
        public long[] extents()
            {
            try
                {
                return getStore().extents();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.extents();
            }

        /**
         * {@inheritDoc}
         */
        public AutoCloseable exclusively()
            {
            try
                {
                return getStore().exclusively();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.exclusively();
            }

        /**
         * {@inheritDoc}
         */
        public R load(long lExtentId, R key)
            {
            try
                {
                return getStore().load(lExtentId, key);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.load(lExtentId, key);
            }

        /**
         * {@inheritDoc}
         */
        public void store(long lExtentId, R key, R value, Object oToken)
            {
            if (oToken instanceof NullPersistentStore.Token)
                {
                // see super.begin
                super.store(lExtentId, key, value, oToken);
                }
            else
                {
                try
                    {
                    getStore().store(lExtentId, key, value, oToken);
                    }
                catch (Throwable t)
                    {
                    onException((T) t);
                    }
                }
            }

        /**
         * {@inheritDoc}
         */
        public void erase(long lExtentId, R key, Object oToken)
            {
            if (oToken instanceof NullPersistentStore.Token)
                {
                // see super.begin
                super.erase(lExtentId, key, oToken);
                }
            else
                {
                try
                    {
                    getStore().erase(lExtentId, key, oToken);
                    }
                catch (Throwable t)
                    {
                    onException((T) t);
                    }
                }
            }

        /**
         * {@inheritDoc}
         */
        public void iterate(Visitor visitor)
            {
            try
                {
                getStore().iterate(visitor);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }
            }

        /**
         * {@inheritDoc}
         */
        public Object begin()
            {
            try
                {
                return getStore().begin();
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.begin();
            }

        /**
         * {@inheritDoc}
         */
        public Object begin(Collector collector, Object oReceipt)
            {
            try
                {
                return getStore().begin(collector, oReceipt);
                }
            catch (Throwable t)
                {
                onException((T) t);
                }

            return super.begin(collector, oReceipt);
            }

        /**
         * {@inheritDoc}
         */
        public void commit(Object oToken)
            {
            if (oToken instanceof NullPersistentStore.Token)
                {
                // see super.begin
                super.commit(oToken);
                }
            else
                {
                try
                    {
                    getStore().commit(oToken);
                    }
                catch (Throwable t)
                    {
                    onException((T) t);
                    }
                }
            }

        /**
         * {@inheritDoc}
         */
        public void abort(Object oToken)
            {
            if (oToken instanceof NullPersistentStore.Token)
                {
                // see super.begin
                super.abort(oToken);
                }
            else
                {
                try
                    {
                    getStore().abort(oToken);
                    }
                catch (Throwable t)
                    {
                    onException((T) t);
                    }
                }
            }

        // ----- Object methods ---------------------------------------------

        /**
         * Return a human readable description of this SafePersistentStore.
         *
         * @return a human readable description
         */
        @Override
        public String toString()
            {
            return "Safe" + String.valueOf(getStore());
            }

        // ----- data members -----------------------------------------------

        /**
         * The underlying PersistentStore.
         */
        protected final PersistentStore f_store;

        /**
         * The failure continuation for this store.
         */
        protected final Continuation f_contFailure;
        }

    // ----- inner interface: FailureContinuationFactory --------------------

    /**
     * FailureContinuationFactory encapsulates failure continuations to handle
     * unexpected exceptions thrown by implementations of the various persistence
     * layers.
     *
     * @param   the type of a raw, environment specific object representation
     * @param   the type of a Throwable failure to protect
     */
    public interface FailureContinuationFactory
        {
        /**
         * Return a failure continuation to handle unexpected exceptions thrown
         * by operations against the specified PersistenceEnvironment.
         *
         * @param env  the PersistenceEnvironment
         *
         * @return a failure continuation
         */
        public Continuation getEnvironmentContinuation(PersistenceEnvironment env);

        /**
         * Return a failure continuation to handle unexpected exceptions thrown
         * by operations against the specified PersistenceManager.
         *
         * @param mgr  the PersistenceManager
         *
         * @return a failure continuation
         */
        public Continuation getManagerContinuation(PersistenceManager mgr);

        /**
         * Return a failure continuation to handle unexpected exceptions thrown
         * by operations against the specified PersistentStore.
         *
         * @param store  the PersistentStore
         *
         * @return a failure continuation
         */
        public Continuation getStoreContinuation(PersistentStore store);
        }

    // ----- constants ------------------------------------------------------

    /**
     * Default failure continuation factory that provides null continuations.
     */
    public static final FailureContinuationFactory DEFAULT_FACTORY =
                new FailureContinuationFactory()
            {
            /**
             * {@inheritDoc}
             */
            public Continuation getEnvironmentContinuation(PersistenceEnvironment env)
                {
                return NullImplementation.getContinuation();
                }

            /**
             * {@inheritDoc}
             */
            public Continuation getManagerContinuation(PersistenceManager mgr)
                {
                return NullImplementation.getContinuation();
                }

            /**
             * {@inheritDoc}
             */
            public Continuation getStoreContinuation(PersistentStore store)
                {
                return NullImplementation.getContinuation();
                }
            };
    }