/******************************************************************************* * Copyright (c) 2010-present Sonatype, Inc. * All rights reserved. This program and the accompanying materials * are 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 * * 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.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<Class<?>, BeanLifecycle> lifecycles = // new ConcurrentHashMap<Class<?>, BeanLifecycle>( 16, 0.75f, 1 ); private final Deque<Object> stoppableBeans = new ArrayDeque<Object>(); // ---------------------------------------------------------------------- // Public methods // ---------------------------------------------------------------------- public boolean manage( final Class<?> clazz ) { return buildLifecycle( clazz ); } public PropertyBinding manage( final BeanProperty<?> property ) { return null; // no custom property bindings } public boolean manage( final Object bean ) { final BeanLifecycle lifecycle = lifecycleFor( bean ); if ( lifecycle.isStoppable() ) { pushStoppable( bean ); } if ( lifecycle.isStartable() ) { schedule( bean ); } return true; } public boolean unmanage( final Object bean ) { if ( removeStoppable( bean ) ) { lifecycleFor( bean ).stop( bean ); } return true; } 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(); } } }