edu.umn.msi.tropix.common.concurrent.impl.CachedSupport.java Source code

Java tutorial

Introduction

Here is the source code for edu.umn.msi.tropix.common.concurrent.impl.CachedSupport.java

Source

/*******************************************************************************
 * Copyright 2009 Regents of the University of Minnesota. All rights
 * reserved.
 * Copyright 2009 Mayo Foundation for Medical Education and Research.
 * All rights reserved.
 *
 * This program is made available under the terms of the Eclipse
 * Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * 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 INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS
 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
 * PARTICULAR PURPOSE.  See the License for the specific language
 * governing permissions and limitations under the License.
 *
 * Contributors:
 * Minnesota Supercomputing Institute - initial API and implementation
 ******************************************************************************/

package edu.umn.msi.tropix.common.concurrent.impl;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import javax.annotation.PostConstruct;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.common.base.Supplier;

import edu.umn.msi.tropix.common.concurrent.Interruptable;
import edu.umn.msi.tropix.common.concurrent.InterruptableExecutor;
import edu.umn.msi.tropix.common.concurrent.InterruptableExecutors;
import edu.umn.msi.tropix.common.concurrent.LoopingRunnable;
import edu.umn.msi.tropix.common.logging.ExceptionUtils;

abstract class CachedSupport<T> {
    private static final Log LOG = LogFactory.getLog(CachedSupport.class);
    private final CountDownLatch isInitialized = new CountDownLatch(1);
    private InterruptableExecutor interruptableExecutor = InterruptableExecutors.getDefault();
    private T cachedInstance = null;
    private Supplier<LoopingRunnable> loopingRunnableSupplier;
    private Executor executor;
    private boolean cache = true;
    private boolean cacheDuringInitialization = true;

    public void setCache(final boolean cache) {
        this.cache = cache;
    }

    public void setCacheDuringInitialization(final boolean cacheDuringInitialization) {
        this.cacheDuringInitialization = cacheDuringInitialization;
    }

    private void setupCachingLoop() {
        final Runnable runnable = new Runnable() {
            public void run() {
                T newInstance = null;
                try {
                    newInstance = getInstance();
                } catch (final Throwable t) {
                    ExceptionUtils.logQuietly(CachedSupport.LOG, t, "Failed to obtain object to cache.");
                }
                if (newInstance != null) {
                    cachedInstance = newInstance;
                }
                isInitialized.countDown();
            }
        };
        final LoopingRunnable loopingRunnable = this.loopingRunnableSupplier.get();
        loopingRunnable.setBaseRunnable(runnable);
        executor.execute(loopingRunnable);
    }

    @PostConstruct
    public void init() {
        if (cache) {
            if (cacheDuringInitialization) {
                setupCachingLoop();
            } else {
                // Avoid bug in spring by letting init() finish before setupCachingLoop needs to.
                Executors.newSingleThreadExecutor().execute(new Runnable() {
                    public void run() {
                        setupCachingLoop();
                    }
                });

            }
        }
    }

    protected abstract T getInstance();

    protected T getCachedInstance() {
        if (cache) {
            interruptableExecutor.execute(new Interruptable() {
                public void run() throws InterruptedException {
                    isInitialized.await();
                }
            });
            return this.cachedInstance;
        } else {
            return getInstance();
        }
    }

    public void setLoopingRunnableSupplier(final Supplier<LoopingRunnable> loopingRunnableSupplier) {
        this.loopingRunnableSupplier = loopingRunnableSupplier;
    }

    public void setInterruptableExecutor(final InterruptableExecutor interruptableExecutor) {
        this.interruptableExecutor = interruptableExecutor;
    }

    public void setExecutor(final Executor executor) {
        this.executor = executor;
    }

}