Package org.directwebremoting.guice.util

Source Code of org.directwebremoting.guice.util.AbstractContextScope

/*
* Copyright 2008 Tim Peierls
*
* 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 org.directwebremoting.guice.util;

import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.util.ToStringBuilder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static java.util.Collections.synchronizedList;

import static org.directwebremoting.guice.util.AbstractContextScope.State.CLOSED;
import static org.directwebremoting.guice.util.AbstractContextScope.State.OPEN;


/**
* Partial implementation of {@link ContextScope}. Concrete implementations
* must pass the context identifier type to the super constructor and define
* {@code get()} to return the current context identifier (and to return null
* or throw an exception if there is no current context). They must also implement
* the {@link ContextRegistry} interface.
* @author Tim Peierls [tim at peierls dot net]
*/
public abstract class AbstractContextScope<C, R> implements ContextScope<C>, ContextRegistry<C, R>
{
    protected AbstractContextScope(Class<C> type, String scopeName)
    {
        this.type = type;
        this.scopeName = scopeName;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString()
    {
        return scopeName;
    }

    /* (non-Javadoc)
     * @see org.directwebremoting.guice.ContextScope#getKeysInScope()
     */
    public List<Key<?>> getKeysInScope()
    {
        synchronized (scopedKeys)
        {
            return new ArrayList<Key<?>>(scopedKeys);
        }
    }

    /* (non-Javadoc)
     * @see org.directwebremoting.guice.ContextScope#scope(com.google.inject.Key, com.google.inject.Provider)
     */
    public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator)
    {
        scopedKeys.add(key);
        final String name = key.toString();
        return new Provider<T>()
        {
            public T get()
            {
                C context = getContext(key);
                R registry = registryFor(context);
                InstanceProvider<T> future = AbstractContextScope.this.get(registry, key, name);
                if (future == null)
                {
                    InstanceProvider<T> futureTask = new FutureTaskProvider<T>(creator);
                    future = putIfAbsent(registry, key, name, futureTask);
                    if (future == null)
                    {
                        future = futureTask;
                        futureTask.run();
                        if (Thread.currentThread().isInterrupted())
                        {
                            remove(registry, key, name, futureTask);
                        }
                    }
                }
                return future.get();
            }

            @Override
            public String toString()
            {
                return new ToStringBuilder(this.getClass())
                    .add("scopeName", scopeName)
                    .add("type", type)
                    .add("key", key)
                    .add("creator", creator)
                    .toString();
            }
        };
    }

    public abstract C get();

    /* (non-Javadoc)
     * @see org.directwebremoting.guice.ContextScope#type()
     */
    public Class<C> type()
    {
        return type;
    }

    /* (non-Javadoc)
     * @see org.directwebremoting.guice.ContextScope#getOpenContexts()
     */
    public Collection<C> getOpenContexts()
    {
        Collection<C> openContexts = new ArrayList<C>();
        for (C context : contexts.keySet())
        {
            if (contexts.get(context) == OPEN)
            {
                openContexts.add(context);
            }
        }
        return openContexts;
    }

    /* (non-Javadoc)
     * @see org.directwebremoting.guice.ContextScope#close(java.lang.Object, org.directwebremoting.guice.ContextCloseHandler<?>[])
     */
    public void close(C context, ContextCloseHandler<?>... closeHandlers)
    {
        if (!contexts.replace(context, OPEN, CLOSED))
        {
            // Context hadn't been opened or was already closed.
            return;
        }

        for (InstanceProvider<?> provider : registeredProviders(registryFor(context)))
        {
            Object value = null;
            try
            {
                value = provider.get();
            }
            catch (RuntimeException e)
            {
                // Ignore runtime exceptions: they were thrown when
                // attempting creation and mean that no object was
                // created.
            }

            if (value == null)
            {
                // No instance was created by this provider, so we ignore.
                continue;
            }

            for (ContextCloseHandler<?> closeHandler : closeHandlers)
            {
                handleClose(closeHandler, value);
            }
        }
    }

    /* (non-Javadoc)
     * @see org.directwebremoting.guice.ContextScope#closeAll(org.directwebremoting.guice.ContextCloseHandler<?>[])
     */
    public void closeAll(ContextCloseHandler<?>... closeHandlers)
    {
        for (C context : getOpenContexts())
        {
            close(context, closeHandlers);
        }
    }

    private <T> void handleClose(ContextCloseHandler<T> closeHandler, Object value)
    {
        Class<T> closeType = closeHandler.type();
        if (closeType.isInstance(value))
        {
            try
            {
                closeHandler.close(closeType.cast(value));
            }
            catch (Exception e)
            {
                // Ignore exceptions when closing,
                // the closeHandler should have taken
                // appropriate action before re-throwing.
            }
        }
    }

    protected C getContext(Key<?> key)
    {
        C context = null;
        RuntimeException caught = null;
        try
        {
            context = get();
            if (contexts.putIfAbsent(context, OPEN) == CLOSED)
            {
                // Context is closed.
                context = null;
            }
        }
        catch (RuntimeException ex)
        {
            caught = ex;
        }
        if (context == null)
        {
            throw new OutOfScopeException(this, key, caught);
        }

        return context;
    }

    private Collection<InstanceProvider<?>> registeredProviders(R registry)
    {
        List<InstanceProvider<?>> providers = new ArrayList<InstanceProvider<?>>();
        for (Key<?> key : getKeysInScope())
        {
            InstanceProvider<?> provider = get(registry, key, key.toString());
            if (provider != null)
            {
                providers.add(provider);
            }
        }
        return providers;
    }

    enum State
    {
        OPEN,
        CLOSED
    }

    protected final Class<C> type;

    protected final String scopeName;

    /* @GuardedBy("self") */
    private final List<Key<?>> scopedKeys = synchronizedList(new ArrayList<Key<?>>());

    private final ConcurrentMap<C, State> contexts = new ConcurrentHashMap<C, State>();
}
TOP

Related Classes of org.directwebremoting.guice.util.AbstractContextScope

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.