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

org.codehaus.plexus.DefaultComponentRegistry Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
package org.codehaus.plexus;

import static com.google.common.base.ReferenceType.WEAK;
import static com.google.common.collect.Iterables.concat;
import com.google.common.collect.ListMultimap;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newConcurrentHashMap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.ReferenceMap;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import static org.codehaus.plexus.component.CastUtils.cast;
import org.codehaus.plexus.component.ComponentIndex;
import static org.codehaus.plexus.component.ComponentStack.pushComponentStack;
import static org.codehaus.plexus.component.ComponentStack.popComponentStack;
import org.codehaus.plexus.component.manager.ComponentManager;
import org.codehaus.plexus.component.manager.ComponentManagerFactory;
import org.codehaus.plexus.component.manager.StaticComponentManager;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
import org.codehaus.plexus.component.repository.ComponentDescriptorListener;
import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.component.repository.exception.ComponentRepositoryException;
import org.codehaus.plexus.lifecycle.LifecycleHandler;
import org.codehaus.plexus.lifecycle.LifecycleHandlerManager;
import org.codehaus.plexus.lifecycle.UndefinedLifecycleHandlerException;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.logging.NullLogger;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;

public class DefaultComponentRegistry implements ComponentRegistry
{
    private static final String DEFAULT_INSTANTIATION_STRATEGY = "singleton";

    private final MutablePlexusContainer container;
    private final LifecycleHandlerManager lifecycleHandlerManager;
    private final Logger logger;

    private final AtomicBoolean disposed = new AtomicBoolean( false );

    private final ConcurrentMap componentManagerFactories = newConcurrentHashMap();

    private final ComponentIndex> index = new ComponentIndex>();
    private final Map, ComponentManager> componentManagersByComponentDescriptor =
        new ReferenceMap, ComponentManager>( WEAK, WEAK);

    private final Map> componentManagersByComponent =
        new ReferenceMap>( WEAK, WEAK);

    private final ListMultimap, String>, ComponentDescriptorListener> listeners = Multimaps.newArrayListMultimap();

    public DefaultComponentRegistry( MutablePlexusContainer container, LifecycleHandlerManager lifecycleHandlerManager )
    {
        this.container = container;
        this.lifecycleHandlerManager = lifecycleHandlerManager;

        Logger containerLogger = container.getLogger();
        if ( containerLogger != null )
        {
            logger = containerLogger;
        }
        else
        {
            logger = new NullLogger();
        }
    }

    public void dispose()
    {
        if (disposed.getAndSet( true )) {
            // already disposed
            return;
        }

        List> managers;
        synchronized ( index )
        {
            managers = new ArrayList>( index.clear() );
            componentManagersByComponentDescriptor.clear();
            componentManagersByComponent.clear();

        }

        // reverse sort the managers by startId
        Collections.sort( managers, new Comparator>() {
            public int compare( ComponentManager left, ComponentManager right )
            {
                if (left.getStartId() < right.getStartId() )
                {
                    return 1;
                }
                else if (left.getStartId() == right.getStartId() )
                {
                    return 0;
                }
                else
                {
                    return -1;
                }
            }
        });

        // Call dispose callback outside of synchronized lock to avoid deadlocks
        for ( ComponentManager componentManager : managers )
        {
            try
            {
                componentManager.dispose();
            }
            catch ( Exception e )
            {
                // todo dain use a monitor instead of a logger
                logger.error( "Error while disposing component manager. Continuing with the rest", e );
            }
            fireComponentDescriptorRemoved( componentManager.getComponentDescriptor() );
        }
    }

    //
    // Component Manager Factories
    //

    public void registerComponentManagerFactory( ComponentManagerFactory componentManagerFactory )
    {
        if ( disposed.get() )
        {
            throw new IllegalStateException("ComponentRegistry has been disposed");
        }

        componentManagerFactories.put( componentManagerFactory.getId(), componentManagerFactory );
    }

    //
    // Component Descriptors
    //

    public  void addComponentDescriptor( ComponentDescriptor componentDescriptor ) throws ComponentRepositoryException
    {
        if ( disposed.get() )
        {
            throw new ComponentRepositoryException("ComponentRegistry has been disposed", componentDescriptor);
        }

        // verify the descriptor matches the role hint and type
        verifyComponentDescriptor( componentDescriptor );

        // Get the ComponentManagerFactory
        String instantiationStrategy = componentDescriptor.getInstantiationStrategy();
        if ( instantiationStrategy == null )
        {
            instantiationStrategy = DEFAULT_INSTANTIATION_STRATEGY;
        }
        ComponentManagerFactory componentManagerFactory = componentManagerFactories.get( instantiationStrategy );
        if ( componentManagerFactory == null )
        {
            throw new ComponentRepositoryException( "Unsupported instantiation strategy: " + instantiationStrategy,
                componentDescriptor );
        }

        // Get the LifecycleHandler
        LifecycleHandler lifecycleHandler;
        try
        {
            lifecycleHandler = lifecycleHandlerManager.getLifecycleHandler( componentDescriptor.getLifecycleHandler() );
        }
        catch ( UndefinedLifecycleHandlerException e )
        {
            throw new ComponentRepositoryException( "Undefined lifecycle handler: " + componentDescriptor.getLifecycleHandler(),
                componentDescriptor );
        }

        // Create the ComponentManager
        ComponentManager componentManager = componentManagerFactory.createComponentManager( container,
            lifecycleHandler,
            componentDescriptor );

        // Add componentManager to indexe
        synchronized ( index )
        {
            index.add( componentDescriptor.getRealm(),
                componentDescriptor.getRoleClass(),
                componentDescriptor.getRoleHint(),
                componentManager);
            componentManagersByComponentDescriptor.put(componentDescriptor, componentManager);
        }

        fireComponentDescriptorAdded( componentDescriptor );
    }

    public  ComponentDescriptor getComponentDescriptor( Class type, String roleHint )
    {
        ComponentManager componentManager = (ComponentManager) index.get( type, roleHint );
        if ( componentManager == null )
        {
            return null;
        }
        return componentManager.getComponentDescriptor();
    }

    public  Map> getComponentDescriptorMap( Class type )
    {
        Map> componentManagers = cast( index.getAllAsMap( type ) );

        Map> descriptors = new LinkedHashMap>(componentManagers.size());
        for ( Entry> entry : componentManagers.entrySet() )
        {
            descriptors.put(entry.getKey(), entry.getValue().getComponentDescriptor());
        }

        return Collections.unmodifiableMap( descriptors );
    }

    public  List> getComponentDescriptorList( Class type )
    {
        List> componentManagers = cast( index.getAll( type ) );

        List> descriptors = new ArrayList>(componentManagers.size());
        for ( ComponentManager componentManager : componentManagers )
        {
            descriptors.add( componentManager.getComponentDescriptor() );
        }

        return Collections.unmodifiableList( descriptors );
    }

    //
    // Component Instances
    //

    public  void addComponent( T instance, Class type, String roleHint, ClassRealm realm ) throws ComponentRepositoryException
    {
        if ( disposed.get() )
        {
            throw new ComponentRepositoryException("ComponentRegistry has been disposed", type, roleHint, realm);
        }

        StaticComponentManager componentManager = new StaticComponentManager( container, instance, type, roleHint, realm );

        // verify descriptor is consistent
        ComponentDescriptor descriptor = componentManager.getComponentDescriptor();
        verifyComponentDescriptor( descriptor );

        synchronized ( index )
        {
            index.add( descriptor.getRealm(), descriptor.getRoleClass(), descriptor.getRoleHint(), componentManager);
            componentManagersByComponentDescriptor.put( descriptor, componentManager);
        }

        fireComponentDescriptorAdded( descriptor );
    }

    public  T lookup( Class type, String roleHint ) throws ComponentLookupException
    {
        // verify arguments
        if ( type == null )
        {
            throw new NullPointerException( "type is null" );
        }
        if ( roleHint == null )
        {
            roleHint = PlexusConstants.PLEXUS_DEFAULT_HINT;
        }

        return getComponent( type, roleHint );
    }

    public  T lookup( ComponentDescriptor componentDescriptor ) throws ComponentLookupException
    {
        ComponentManager componentManager = (ComponentManager) componentManagersByComponentDescriptor.get( componentDescriptor );
        if ( componentManager == null )
        {
            throw new ComponentLookupException( "Component descriptor is not registered with PlexusContainer", componentDescriptor );
        }
        return getComponent( componentManager );
    }

    public  Map lookupMap( Class type, List roleHints )
        throws ComponentLookupException
    {
        // verify arguments
        if ( type == null )
        {
            throw new NullPointerException( "type is null" );
        }

        // if no hints provided, get all valid hints for this role
        Map components = new LinkedHashMap();
        if ( roleHints == null )
        {
            Map> componentManagers = cast( index.getAllAsMap( type ) );

            for ( Entry> entry : componentManagers.entrySet() )
            {
                String roleHint = entry.getKey();
                ComponentManager componentManager = entry.getValue();

                // todo dain catch the exception... it isn't the callers problem when one component in a collection fails
                T component = getComponent( componentManager );
                components.put( roleHint, component);
            }
        }
        else
        {
            for ( String roleHint : roleHints )
            {
                // todo dain catch the exception... it isn't the callers problem when one component in a collection fails
                T component = getComponent( type, roleHint );
                components.put( roleHint, component );
            }
        }

        return components;
    }

    public  List lookupList( Class type, List roleHints ) throws ComponentLookupException
    {
        // verify arguments
        if ( type == null )
        {
            throw new NullPointerException( "type is null" );
        }

        // if no hints provided, get all valid hints for this role
        List components = new ArrayList();
        if ( roleHints == null )
        {
            List> componentManagers = cast( index.getAll( type ) );
            for ( ComponentManager componentManager : componentManagers )
            {
                // todo dain catch the exception... it isn't the callers problem when one component in a collection fails
                T component = getComponent( componentManager );
                components.add( component);
            }
        }
        else
        {
            for ( String roleHint : roleHints )
            {
                // todo dain catch the exception... it isn't the callers problem when one component in a collection fails
                T component = getComponent( type, roleHint );
                components.add( component );
            }
        }

        return components;
    }

    public  void addComponentDescriptorListener( ComponentDescriptorListener listener )
    {
        Class type = listener.getType();
        List roleHints = listener.getRoleHints();
        synchronized ( this )
        {
            if (roleHints == null )
            {
                listeners.put(new Pair, String>(type, null), listener);
            }
            else
            {
                for ( String roleHint : roleHints )
                {
                    listeners.put(new Pair, String>(type, roleHint), listener);
                }
            }
        }

        // if no hints provided, get all valid hints for this role
        if ( roleHints == null )
        {
            List> componentManagers = cast( index.getAll( type ) );
            for ( ComponentManager componentManager : componentManagers )
            {
                listener.componentDescriptorAdded( componentManager.getComponentDescriptor() );
            }
        }
        else
        {
            for ( String roleHint : roleHints )
            {
                ComponentManager componentManager = (ComponentManager) index.get( type, roleHint );
                if (componentManager != null) {
                    listener.componentDescriptorAdded( componentManager.getComponentDescriptor() );
                }
            }
        }
    }

    public synchronized  void removeComponentDescriptorListener( ComponentDescriptorListener listener )
    {
        Class type = listener.getType();
        List roleHints = listener.getRoleHints();
        if (roleHints == null || roleHints.isEmpty())
        {
            listeners.remove(new Pair, String>(type, null), listener);
        }
        else
        {
            for ( String roleHint : roleHints )
            {
                listeners.remove(new Pair, String>(type, roleHint), listener);
            }
        }
    }

    private synchronized  List> getListeners(ComponentDescriptor descriptor)
    {
        List> allHintListeners =
            cast( listeners.get( new Pair, String>( descriptor.getRoleClass(), null ) ) );
        List> specificHintListeners =
            cast( listeners.get( new Pair, String>( descriptor.getRoleClass(), descriptor.getRoleHint() ) ) );

        return newArrayList( concat(allHintListeners, specificHintListeners) );
    }

    private  void fireComponentDescriptorAdded( ComponentDescriptor componentDescriptor )
    {
        for ( ComponentDescriptorListener listener : getListeners( componentDescriptor ))
        {
            try
            {
                listener.componentDescriptorAdded( componentDescriptor );
            }
            catch ( Throwable e )
            {
                logger.debug( "ComponentDescriptorListener threw exception while processing " + componentDescriptor, e );
            }
        }
    }

    private  void fireComponentDescriptorRemoved( ComponentDescriptor componentDescriptor )
    {
        for ( ComponentDescriptorListener listener : getListeners( componentDescriptor ))
        {
            try
            {
                listener.componentDescriptorRemoved( componentDescriptor );
            }
            catch ( Throwable e )
            {
                logger.error( "ComponentDescriptorListener threw exception while processing " + componentDescriptor, e );
            }
        }
    }

    public void release( Object component ) throws ComponentLifecycleException
    {
        if ( component == null )
        {
            return;
        }

        // get the component manager
        ComponentManager componentManager = componentManagersByComponent.get( component );

        if ( componentManager == null )
        {
            // This needs to be tracked down but the user doesn't need to see this
            // during the maven bootstrap this logger is null.
            //logger.debug( "Component manager not found for returned component. Ignored. component=" + component );
            return;
        }

        // release the component from the manager
        componentManager.release( component );
    }

    public void removeComponentRealm( ClassRealm classRealm ) throws PlexusContainerException
    {
        try
        {
            // remove all component managers associated with the realm
            LinkedHashSet> dispose;
            synchronized ( index )
            {
                dispose = new LinkedHashSet>(index.removeAll( classRealm ));
                for ( ComponentManager componentManager : dispose )
                {
                    ComponentDescriptor descriptor = componentManager.getComponentDescriptor();
                    componentManagersByComponentDescriptor.remove( descriptor );
                    fireComponentDescriptorRemoved( descriptor );
                }
            }

            // Call dispose callback outside of synchronized lock to avoid deadlocks
            for ( ComponentManager componentManager : dispose )
            {
                componentManager.dispose();
            }
        }
        catch ( ComponentLifecycleException e )
        {
            throw new PlexusContainerException( "Failed to dissociate component realm: " + classRealm.getId(), e );
        }
    }

    private  T getComponent( Class type, String roleHint ) throws ComponentLookupException
    {
        ComponentManager componentManager = (ComponentManager) index.get( type, roleHint );
        if ( componentManager == null )
        {
            throw new ComponentLookupException( "Component descriptor cannot be found", type, roleHint );
        }
        return getComponent( componentManager );
    }

    private  T getComponent( ComponentManager componentManager ) throws ComponentLookupException
    {
        ComponentDescriptor descriptor = componentManager.getComponentDescriptor();

        // Get instance from manager... may result in creation
        pushComponentStack( descriptor );
        try
        {
            T component = componentManager.getComponent();

            componentManagersByComponent.put( component, componentManager );

            return component;
        }
        catch ( Exception e )
        {
            // get real cause
            Throwable cause = e.getCause();
            if ( cause == null )
            {
                cause = e;
            }

            // do not rewrap ComponentLookupException
            if (cause instanceof ComponentLookupException )
            {
                throw (ComponentLookupException) cause;
            }

            throw new ComponentLookupException( e.getMessage(), descriptor, cause );
        }
        finally
        {
            popComponentStack();
        }
    }

    private  void verifyComponentDescriptor( ComponentDescriptor descriptor ) throws ComponentRepositoryException
    {
        ClassLoader classLoader = descriptor.getRealm();
        if ( classLoader == null)
        {
            throw new ComponentRepositoryException( "ComponentDescriptor realm is null", descriptor);
        }

        Class implementationClass = descriptor.getImplementationClass();
        if (implementationClass.equals( Object.class ))
        {
            throw new ComponentRepositoryException( "ComponentDescriptor implementation class could not be loaded", descriptor);
        }

        String role = descriptor.getRole();
        if (role == null)
        {
            throw new ComponentRepositoryException( "ComponentDescriptor role is null", descriptor);
        }

        Class roleClass;
        try
        {
            roleClass = classLoader.loadClass( role );
        }
        catch ( ClassNotFoundException e )
        {
            throw new ComponentRepositoryException( "ComponentDescriptor role class can not be loaded", descriptor);
        }

        if (!roleClass.isAssignableFrom( implementationClass ))
        {
            throw new ComponentRepositoryException( "ComponentDescriptor implementation class does not implement the role class:" +
                " implementationClass=" + implementationClass.getName() + " roleClass=" + roleClass.getName(),
                descriptor);
        }
    }

    public static class Pair {
        private final L left;
        private final R right;

        public Pair( L left, R right )
        {
            this.left = left;
            this.right = right;
        }

        public L getLeft()
        {
            return left;
        }

        public R getRight()
        {
            return right;
        }

        public boolean equals( Object o )
        {
            if ( this == o )
            {
                return true;
            }
            if ( !( o instanceof Pair ) )
            {
                return false;
            }

            Pair pair = (Pair) o;

            return
                ( left == null ? pair.left == null : left.equals( pair.left ) ) && 
                ( right == null ? pair.right == null : right.equals( pair.right ) );

        }

        public int hashCode()
        {
            int result;
            result = ( left != null ? left.hashCode() : 0 );
            result = 31 * result + ( right != null ? right.hashCode() : 0 );
            return result;
        }

        public String toString()
        {
            StringBuilder buf = new StringBuilder( );
            buf.append("[").append(left).append(", ").append(right).append("]");
            return buf.toString();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy