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

org.eclipse.sisu.bean.LifecycleManager Maven / Gradle / Ivy

There is a newer version: 3.0.0-alpha-3
Show newest version
/*
 * Copyright (c) 2010-2024 Sonatype, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
 */
package org.eclipse.sisu.bean;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * {@link BeanManager} that manages JSR250 beans and schedules lifecycle events.
 */
public final class LifecycleManager
    extends BeanScheduler
    implements BeanManager
{
    // ----------------------------------------------------------------------
    // Implementation fields
    // ----------------------------------------------------------------------

    private final LifecycleBuilder builder = new LifecycleBuilder();

    private final Map, BeanLifecycle> lifecycles = //
        new ConcurrentHashMap, BeanLifecycle>( 16, 0.75f, 1 );

    private final Deque stoppableBeans = new ArrayDeque();

    // ----------------------------------------------------------------------
    // Public methods
    // ----------------------------------------------------------------------

    @Override
    public boolean manage( final Class clazz )
    {
        return buildLifecycle( clazz );
    }

    @Override
    public PropertyBinding manage( final BeanProperty property )
    {
        return null; // no custom property bindings
    }

    @Override
    public boolean manage( final Object bean )
    {
        final BeanLifecycle lifecycle = lifecycleFor( bean );
        if ( lifecycle.isStoppable() )
        {
            pushStoppable( bean );
        }
        if ( lifecycle.isStartable() )
        {
            schedule( bean );
        }
        return true;
    }

    @Override
    public boolean unmanage( final Object bean )
    {
        if ( removeStoppable( bean ) )
        {
            lifecycleFor( bean ).stop( bean );
        }
        return true;
    }

    @Override
    public boolean unmanage()
    {
        for ( Object bean; ( bean = popStoppable() ) != null; )
        {
            lifecycleFor( bean ).stop( bean );
        }
        return true;
    }

    // ----------------------------------------------------------------------
    // Customized methods
    // ----------------------------------------------------------------------

    @Override
    protected void activate( final Object bean )
    {
        lifecycleFor( bean ).start( bean );
    }

    // ----------------------------------------------------------------------
    // Implementation methods
    // ----------------------------------------------------------------------

    /**
     * Attempts to build a JSR250 lifecycle for the given bean type.
     * 
     * @param clazz The bean type
     * @return {@code true} if the bean defines a lifecycle; otherwise {@code false}
     */
    private boolean buildLifecycle( final Class clazz )
    {
        BeanLifecycle lifecycle = lifecycles.get( clazz );
        if ( null == lifecycle )
        {
            lifecycle = builder.build( clazz );
            lifecycles.put( clazz, lifecycle );
        }
        return lifecycle != BeanLifecycle.NO_OP;
    }

    /**
     * Looks up the JSR250 lifecycle previously built for this bean.
     * 
     * @param bean The bean instance
     * @return Lifecycle for the bean
     */
    private BeanLifecycle lifecycleFor( final Object bean )
    {
        if ( null != bean )
        {
            // check the class hierarchy, just in case the bean instance has been proxied/enhanced
            for ( Class c = bean.getClass(); null != c && c != Object.class; c = c.getSuperclass() )
            {
                final BeanLifecycle lifecycle = lifecycles.get( c );
                if ( null != lifecycle )
                {
                    return lifecycle;
                }
            }
        }
        return BeanLifecycle.NO_OP;
    }

    private void pushStoppable( final Object bean )
    {
        synchronized ( stoppableBeans )
        {
            stoppableBeans.addLast( bean );
        }
    }

    private boolean removeStoppable( final Object bean )
    {
        synchronized ( stoppableBeans )
        {
            return stoppableBeans.remove( bean );
        }
    }

    private Object popStoppable()
    {
        synchronized ( stoppableBeans )
        {
            return stoppableBeans.pollLast();
        }
    }

    /**
     * Flush the cache for each key that satisfies the given predicate
     * 
     * @param remove a tester that can decide if this key needs to be flushed or
     *               not.
     * @since 0.9.0.M3
     */
    public void flushCacheFor( ClassTester remove )
    {
        for ( Iterator> iterator = lifecycles.keySet().iterator(); iterator.hasNext(); )
        {
            if ( remove.shouldFlush( iterator.next() ) )
            {
                iterator.remove();
            }
        }
    }

    /**
     * Allows testing if a class should be flushed from the cache
     *
     * @since 0.9.0.M3
     */
    public static interface ClassTester
    {

        /**
         * Test if class should be flushed
         * 
         * @param clz the class to test
         * @return true if class must be flushed, false
         *         otherwise
         */
        boolean shouldFlush( Class clz );

    }
}