Package org.codehaus.plexus

Source Code of org.codehaus.plexus.DefaultPlexusContainer

package org.codehaus.plexus;

/*
* Copyright 2001-2006 Codehaus Foundation.
*
* 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.
*/

import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
import org.codehaus.plexus.component.composition.ComponentComposerManager;
import org.codehaus.plexus.component.composition.CompositionException;
import org.codehaus.plexus.component.composition.setter.SetterComponentComposer;
import org.codehaus.plexus.component.configurator.BasicComponentConfigurator;
import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
import org.codehaus.plexus.component.configurator.ComponentConfigurator;
import org.codehaus.plexus.component.discovery.ComponentDiscovererManager;
import org.codehaus.plexus.component.discovery.ComponentDiscoveryListener;
import org.codehaus.plexus.component.discovery.PlexusXmlComponentDiscoverer;
import org.codehaus.plexus.component.factory.ComponentFactoryManager;
import org.codehaus.plexus.component.manager.ComponentManager;
import org.codehaus.plexus.component.manager.ComponentManagerManager;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
import org.codehaus.plexus.component.repository.ComponentRepository;
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.component.repository.io.PlexusTools;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.configuration.PlexusConfigurationException;
import org.codehaus.plexus.configuration.PlexusConfigurationMerger;
import org.codehaus.plexus.configuration.processor.ConfigurationProcessingException;
import org.codehaus.plexus.configuration.processor.ConfigurationProcessor;
import org.codehaus.plexus.configuration.processor.ConfigurationResourceNotFoundException;
import org.codehaus.plexus.configuration.processor.DirectoryConfigurationResourceHandler;
import org.codehaus.plexus.configuration.processor.FileConfigurationResourceHandler;
import org.codehaus.plexus.container.initialization.ComponentDiscoveryPhase;
import org.codehaus.plexus.container.initialization.ContainerInitializationContext;
import org.codehaus.plexus.container.initialization.ContainerInitializationException;
import org.codehaus.plexus.container.initialization.ContainerInitializationPhase;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.context.ContextMapAdapter;
import org.codehaus.plexus.context.DefaultContext;
import org.codehaus.plexus.lifecycle.LifecycleHandlerManager;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.logging.LoggerManager;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.InterpolationFilterReader;
import org.codehaus.plexus.util.ReaderFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

/**
* <pre>
*  //TODO move lookup code to a separate component
*  //TODO  register live components so they can be wired
*  //keep track of the interfaces for components
*  //todo allow setting of a live configuraton so applications that embed plexus can use
*  whatever configuration mechanism they like. They just have to adapt it into something plexus can understand.
*  //todo
*  make a typesafe configuration model for the container
*  //todo pico like registration
*  //todo need loggers per execution in the maven embedder
*  //todo a simple front-end to make containers of different flavours, a flavour encapsulating
*  // a set of behaviours
*  //todo the core components should probably have a small lifecycle to pass through
* </pre>
*
* @author Jason van Zyl
* @author Kenney Westerhof
*/
public class DefaultPlexusContainer
    extends AbstractLogEnabled
    implements MutablePlexusContainer
{
    protected static final String DEFAULT_CONTAINER_NAME = "default";

    protected static final String DEFAULT_REALM_NAME = "plexus.core";

    protected String name;

    protected PlexusContainer parentContainer;

    protected DefaultContext containerContext;

    protected PlexusConfiguration configuration;

    // todo: don't use a reader
    protected Reader configurationReader;

    protected ClassWorld classWorld;

    protected ClassRealm containerRealm;

    // ----------------------------------------------------------------------------
    // Core components
    // ----------------------------------------------------------------------------

    protected List initializationPhases;

    protected ComponentRepository componentRepository;

    protected ComponentManagerManager componentManagerManager;

    protected LifecycleHandlerManager lifecycleHandlerManager;

    protected ComponentDiscovererManager componentDiscovererManager;

    protected ComponentFactoryManager componentFactoryManager;

    protected ComponentLookupManager componentLookupManager;

    protected ComponentComposerManager componentComposerManager;

    protected LoggerManager loggerManager;

    // ----------------------------------------------------------------------------
    //
    // ----------------------------------------------------------------------------

    /**
     * Map&lt;String, PlexusContainer> where the key is the container name.
     */
    protected Map childContainers = new WeakHashMap();

    protected Date creationDate = new Date();

    protected boolean reloadingEnabled;

    private ThreadLocal lookupRealm = new ThreadLocal();

    /**
     * Used for getLookupRealm for threads when the threadlocal
     * doesn't contain a value.
     */
    private ClassRealm staticLookupRealm;

    public ClassRealm setLookupRealm( ClassRealm realm )
    {
        if ( realm == null )
        {
            return null;
        }

        staticLookupRealm = realm;

        ClassRealm oldRealm = (ClassRealm) lookupRealm.get();

        lookupRealm.set( realm );

        return oldRealm;
    }

    public ClassRealm getLookupRealm()
    {
        ClassRealm cr = (ClassRealm) lookupRealm.get();
        return cr == null ? staticLookupRealm : cr;
    }

    // ----------------------------------------------------------------------
    // Constructors
    // ----------------------------------------------------------------------

    public DefaultPlexusContainer()
        throws PlexusContainerException
    {
        construct( new DefaultContainerConfiguration() );
    }


    public DefaultPlexusContainer( ContainerConfiguration c )
        throws PlexusContainerException
    {
        construct( c );
    }

    // ----------------------------------------------------------------------------
    // Inheritance of Containers
    // ----------------------------------------------------------------------------

    protected DefaultPlexusContainer( String name, Map context, PlexusContainer parent, List discoveryListeners )
        throws PlexusContainerException
    {
        this.parentContainer = parent;

        this.loggerManager = parentContainer.getLoggerManager();

        this.containerRealm = getChildRealm( getName(), name, parent.getContainerRealm() );

        for ( Iterator it = discoveryListeners.iterator(); it.hasNext(); )
        {
            registerComponentDiscoveryListener( (ComponentDiscoveryListener) it.next() );
        }

        ContainerConfiguration c = new DefaultContainerConfiguration()
            .setName( name )
            .setContext( context )
            .setClassWorld( containerRealm.getWorld() )
            .setRealm( containerRealm );

        construct( c );
    }

    // ----------------------------------------------------------------------------
    // Lookup
    // ----------------------------------------------------------------------------

    public Object lookup( String componentKey )
        throws ComponentLookupException
    {
        return lookup( componentKey, getLookupRealm() );
    }

    public Object lookup( String componentKey, ClassRealm realm )
        throws ComponentLookupException
    {
        return componentLookupManager.lookup( componentKey, realm );
    }

    public Map lookupMap( String role )
        throws ComponentLookupException
    {
        return lookupMap( role, getLookupRealm() );
    }

    public Map lookupMap( String role, ClassRealm realm )
        throws ComponentLookupException
    {
        return componentLookupManager.lookupMap( role, realm );
    }

    public List lookupList( String role )
        throws ComponentLookupException
    {
        return lookupList( role, getLookupRealm() );
    }

    public List lookupList( String role, ClassRealm realm )
        throws ComponentLookupException
    {
        return componentLookupManager.lookupList( role, realm );
    }

    public Object lookup( String role, String roleHint )
        throws ComponentLookupException
    {
        return componentLookupManager.lookup( role, roleHint, getLookupRealm() );
    }

    public Object lookup( String role, String roleHint, ClassRealm realm )
        throws ComponentLookupException
    {
        return componentLookupManager.lookup( role, roleHint, realm );
    }

    public Object lookup( Class componentClass )
        throws ComponentLookupException
    {
        return lookup( componentClass, getLookupRealm() );
    }

    public Object lookup( Class componentClass, ClassRealm realm )
        throws ComponentLookupException
    {
        return componentLookupManager.lookup( componentClass, realm );
    }

    public Map lookupMap( Class role )
        throws ComponentLookupException
    {
        return lookupMap( role, getLookupRealm() );

    }

    public Map lookupMap( Class role, ClassRealm realm )
        throws ComponentLookupException
    {
        return componentLookupManager.lookupMap( role, realm );
    }

    public List lookupList( Class role )
        throws ComponentLookupException
    {
        return lookupList( role, getLookupRealm() );
    }

    public List lookupList( Class role, ClassRealm realm )
        throws ComponentLookupException
    {
        return componentLookupManager.lookupList( role, realm );
    }

    public Object lookup( Class role, String roleHint )
        throws ComponentLookupException
    {
        return lookup( role, roleHint, getLookupRealm() );
    }

    public Object lookup( Class role, String roleHint, ClassRealm realm )
        throws ComponentLookupException
    {
        return componentLookupManager.lookup( role, roleHint, realm );
    }

    // ----------------------------------------------------------------------
    // Timestamping Methods
    // ----------------------------------------------------------------------

    public Date getCreationDate()
    {
        return creationDate;
    }

    // ----------------------------------------------------------------------
    // Child container access
    // ----------------------------------------------------------------------

    public boolean hasChildContainer( String name )
    {
        return childContainers.get( name ) != null;
    }

    public void removeChildContainer( String name )
    {
        childContainers.remove( name );
    }

    public PlexusContainer getChildContainer( String name )
    {
        return (PlexusContainer) childContainers.get( name );
    }

    // ----------------------------------------------------------------------------
    // Requirements
    // ----------------------------------------------------------------------------
    // o discover all components that are present in the artifact
    // o create a separate realm for the components
    // o retrieve all the dependencies for the artifact: this last part unfortunately
    // only works in Maven where artifacts are downloaded
    // ----------------------------------------------------------------------------
    public ClassRealm createComponentRealm( String id, List jars )
        throws PlexusContainerException
    {
        ClassRealm componentRealm;

        try
        {
            // XXX this could NOT be a child realm for this container!

            ClassRealm realm = classWorld.getRealm( id );
            getLogger()
                .warn( "Reusing existing component realm: " + id + " - no components detected!", new Throwable() );
            return realm;
        }
        catch ( NoSuchRealmException e )
        {
        }

        try
        {
            componentRealm = containerRealm.createChildRealm( id );
        }
        catch ( DuplicateRealmException e )
        {
            throw new PlexusContainerException( "Error creating child realm.", e );
        }

        try
        {
            for ( Iterator it = jars.iterator(); it.hasNext(); )
            {
                componentRealm.addURL( ( (File) it.next() ).toURI().toURL() );
            }
        }
        catch ( MalformedURLException e )
        {
            throw new PlexusContainerException( "Error adding JARs to realm.", e );
        }

        getLogger().debug( "Created component realm: " + id );

        // ----------------------------------------------------------------------------
        // Discover the components that are present in the new componentRealm.
        // ----------------------------------------------------------------------------

        try
        {
            discoverComponents( componentRealm );
        }
        catch ( PlexusConfigurationException e )
        {
            throw new PlexusContainerException( "Error configuring discovered component.", e );
        }
        catch ( ComponentRepositoryException e )
        {
            throw new PlexusContainerException( "Error resolving discovered component.", e );
        }

        return componentRealm;
    }

    // ----------------------------------------------------------------------------
    // The method from alpha-9 for creating child containers
    // ----------------------------------------------------------------------------

    /**
     * @deprecated
     */
    public PlexusContainer createChildContainer( String name, List classpathJars, Map context )
        throws PlexusContainerException
    {
        return createChildContainer( name, classpathJars, context, Collections.EMPTY_LIST );
    }

    // not sure this is the best strategy, i might just want to take the world. what are the strategies
    // for getting this work properly
    //
    //
    // container with classworld and in the case of developing with maven and wanting to startup
    // waffle what do i need:
    //
    // add project deps to container
    // have new components discoveryed
    // use classes from parent container so that the classloaders are hooked up
    //
    // so do i want to make a classloader or use a realm
    public PlexusContainer createChildContainer( String name, ClassLoader classLoader )
        throws PlexusContainerException
    {
        if ( hasChildContainer( name ) )
        {
            throw new DuplicateChildContainerException( getName(), name );
        }

        ContainerConfiguration c = new DefaultContainerConfiguration()
            .setName( name )
            .setClassWorld( new ClassWorld( name, classLoader ) );

        return new DefaultPlexusContainer( c );
    }

    public PlexusContainer createChildContainer( String name, List classpathJars, Map context, List discoveryListeners )
        throws PlexusContainerException
    {
        if ( hasChildContainer( name ) )
        {
            throw new DuplicateChildContainerException( getName(), name );
        }

        DefaultPlexusContainer child = new DefaultPlexusContainer( name, context, this, discoveryListeners );

        for ( Iterator i = classpathJars.iterator(); i.hasNext(); )
        {
            File jar = (File) i.next();

            child.addJarResource( jar );
        }

        childContainers.put( name, child );

        return child;
    }

    private static ClassRealm getChildRealm( String parentName, String name, ClassRealm containerRealm )
        throws PlexusContainerException
    {
        String childRealmId = parentName + ".child-container[" + name + "]";

        try
        {
            // FIXME: an existing realm probably is in use and already
            // has a parent realm; is it safe to change that?
            ClassRealm childRealm = containerRealm.getWorld().getRealm( childRealmId );
            childRealm.setParentRealm( containerRealm );

            return childRealm;
        }
        catch ( NoSuchRealmException e )
        {
            try
            {
                return containerRealm.createChildRealm( childRealmId );
            }
            catch ( DuplicateRealmException impossibleError )
            {
                throw new PlexusContainerException( "Error creating new realm: After getRealm() failed, newRealm() "
                    + "produced duplication error on same id!", impossibleError );
            }
        }
    }

    // XXX remove
    public void setName( String name )
    {
        this.name = name;
    }

    // XXX remove!
    public void setParentPlexusContainer( PlexusContainer container )
    {
        this.parentContainer = container;
    }

    // ----------------------------------------------------------------------
    // Component Descriptor Lookup
    // ----------------------------------------------------------------------

    public ComponentDescriptor getComponentDescriptor( String role )
    {
        return getComponentDescriptor( role, getLookupRealm() );
    }

    public ComponentDescriptor getComponentDescriptor( String role, ClassRealm realm )
    {
        return getComponentDescriptor( role, PlexusConstants.PLEXUS_DEFAULT_HINT, realm );
    }

    public ComponentDescriptor getComponentDescriptor( String role, String hint )
    {
        return getComponentDescriptor( role, hint, getLookupRealm() );
    }

    public ComponentDescriptor getComponentDescriptor( String role, String hint, ClassRealm classRealm )
    {
        ComponentDescriptor result = componentRepository.getComponentDescriptor( role, hint, classRealm );

        ClassRealm tmpRealm = classRealm.getParentRealm();

        while ( result == null && tmpRealm != null )
        {
            result = componentRepository.getComponentDescriptor( role, hint, classRealm );
            tmpRealm = tmpRealm.getParentRealm();
        }

        if ( result == null && parentContainer != null )
        {
            result = parentContainer.getComponentDescriptor( role, hint, classRealm );
        }

        return result;
    }

    public Map getComponentDescriptorMap( String role )
    {
        return getComponentDescriptorMap( role, getLookupRealm() );
    }

    public Map getComponentDescriptorMap( String role, ClassRealm realm )
    {
        Map result = new WeakHashMap();

        if ( parentContainer != null )
        {
            Map m = parentContainer.getComponentDescriptorMap( role, realm );
            if ( m != null )
            {
                result.putAll( m );
            }
        }

        Map componentDescriptors = componentRepository.getComponentDescriptorMap( role, realm );

        if ( componentDescriptors != null )
        {
            result.putAll( componentDescriptors );
        }

        return result;
    }

    public List getComponentDescriptorList( String role )
    {
        return getComponentDescriptorList( role, getLookupRealm() );
    }

    public List getComponentDescriptorList( String role, ClassRealm realm )
    {
        Map componentDescriptors = getComponentDescriptorMap( role, realm );

        return new ArrayList( componentDescriptors.values() );
    }

    public void addComponentDescriptor( ComponentDescriptor componentDescriptor )
        throws ComponentRepositoryException
    {
        componentRepository.addComponentDescriptor( componentDescriptor );
    }

    // ----------------------------------------------------------------------
    // Component Release
    // ----------------------------------------------------------------------

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

        ComponentManager componentManager = componentManagerManager.findComponentManagerByComponentInstance( component );

        if ( componentManager == null )
        {
            if ( parentContainer != null )
            {
                parentContainer.release( component );
            }
            else
            {
                getLogger()
                    .warn( "Component manager not found for returned component. Ignored. component=" + component );
            }
        }
        else
        {
            componentManager.release( component );

            if ( componentManager.getConnections() <= 0 )
            {
                componentManagerManager.unassociateComponentWithComponentManager( component );
            }
        }
    }

    public void releaseAll( Map components )
        throws ComponentLifecycleException
    {
        for ( Iterator i = components.values().iterator(); i.hasNext(); )
        {
            Object component = i.next();

            release( component );
        }
    }

    public void releaseAll( List components )
        throws ComponentLifecycleException
    {
        for ( Iterator i = components.iterator(); i.hasNext(); )
        {
            Object component = i.next();

            release( component );
        }
    }

    public boolean hasComponent( String componentKey )
    {
        return hasComponent( componentKey, getLookupRealm() );
    }

    public boolean hasComponent( String componentKey, ClassRealm realm )
    {
        return componentRepository.hasComponent( componentKey, realm );
    }

    public boolean hasComponent( String role, String roleHint )
    {
        return hasComponent( role, roleHint, getLookupRealm() );
    }

    public boolean hasComponent( String role, String roleHint, ClassRealm realm )
    {
        return componentRepository.hasComponent( role, roleHint, realm );
    }

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

        ComponentManager componentManager = componentManagerManager.findComponentManagerByComponentInstance( component );

        componentManager.suspend( component );
    }

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

        ComponentManager componentManager = componentManagerManager.findComponentManagerByComponentInstance( component );

        componentManager.resume( component );
    }

    // ----------------------------------------------------------------------
    // Lifecycle Management
    // ----------------------------------------------------------------------

    boolean initialized;

    private void construct( ContainerConfiguration c )
        throws PlexusContainerException
    {
        this.name = c.getName();

        // ----------------------------------------------------------------------------
        // ClassWorld
        // ----------------------------------------------------------------------------

        this.classWorld = c.getClassWorld();

        // Make sure we have a valid ClassWorld
        if ( this.classWorld == null )
        {
            this.classWorld = new ClassWorld( DEFAULT_REALM_NAME, Thread.currentThread().getContextClassLoader() );
        }

        containerRealm = c.getRealm();

        if ( containerRealm == null )
        {
            try
            {
                containerRealm = this.classWorld.getRealm( DEFAULT_REALM_NAME );
            }
            catch ( NoSuchRealmException e )
            {
                List realms = new LinkedList( this.classWorld.getRealms() );

                containerRealm = (ClassRealm) realms.get( 0 );

                if ( containerRealm == null )
                {
                    System.err.println( "No container realm! Expect errors." );

                    new Throwable().printStackTrace();
                }
            }
        }

        setLookupRealm( containerRealm );

        // ----------------------------------------------------------------------------
        // Context
        // ----------------------------------------------------------------------------

        this.containerContext = new DefaultContext();

        if ( c.getContext() != null )
        {
            for ( Iterator it = c.getContext().entrySet().iterator(); it.hasNext(); )
            {
                Map.Entry entry = (Map.Entry) it.next();

                addContextValue( entry.getKey(), entry.getValue() );
            }
        }

        // ----------------------------------------------------------------------------
        // Configuration
        // ----------------------------------------------------------------------------

        // TODO: just store reference to the configuration in a String and use that in the configuration initialization

        InputStream in = null;

        if ( c.getContainerConfiguration() != null )
        {
            String resource = c.getContainerConfiguration();

            if ( resource.startsWith( "/" ) )
            {
                resource = resource.substring( 1 );
            }

            in = toStream( resource );
        }

        try
        {
            this.configurationReader = in == null ? null : ReaderFactory.newXmlReader( in );
        }
        catch ( IOException e )
        {
            throw new PlexusContainerException( "Error reading configuration file", e );
        }

        try
        {
            // XXX this will set up the configuration and process it
            initialize();

            // XXX this will wipe out the configuration field - is this needed? If so,
            // why? can we remove the need to have a configuration field then?
            start();
        }
        finally
        {
            IOUtil.close( this.configurationReader );
        }
    }

    protected void initialize()
        throws PlexusContainerException
    {
        if ( initialized )
        {
            throw new PlexusContainerException( "The container has already been initialized!" );
        }

        try
        {
            initializeConfiguration();

            initializePhases();
        }
        catch ( ContextException e )
        {
            throw new PlexusContainerException( "Error processing configuration", e );
        }
        catch ( ConfigurationProcessingException e )
        {
            throw new PlexusContainerException( "Error processing configuration", e );
        }
        catch ( ConfigurationResourceNotFoundException e )
        {
            throw new PlexusContainerException( "Error processing configuration", e );
        }
        catch ( PlexusConfigurationException e )
        {
            throw new PlexusContainerException( "Error configuring components", e );
        }
        catch ( IOException e )
        {
            throw new PlexusContainerException( "Error reading configuration file", e );
        }

        initialized = true;
    }

    protected void initializePhases()
        throws PlexusContainerException
    {
        PlexusConfiguration initializationConfiguration = configuration.getChild( "container-initialization" );

        ContainerInitializationContext initializationContext = new ContainerInitializationContext(
            this,
            classWorld,
            containerRealm,
            configuration );

        // PLXAPI: I think we might only ever need one of these so maybe we can create it with a constructor
        // and store it.
        ComponentConfigurator c = new BasicComponentConfigurator();

        try
        {
            c.configureComponent( this, initializationConfiguration, containerRealm );
        }
        catch ( ComponentConfigurationException e )
        {
            throw new PlexusContainerException( "Error setting container initialization initializationPhases.", e );
        }

        for ( Iterator iterator = initializationPhases.iterator(); iterator.hasNext(); )
        {
            ContainerInitializationPhase phase = (ContainerInitializationPhase) iterator.next();

            try
            {
                phase.execute( initializationContext );
            }
            catch ( ContainerInitializationException e )
            {
                throw new PlexusContainerException( "Error initializaing container in " + phase + ".", e );
            }
        }
    }

    // We need to be aware of dependencies between discovered components when the listed component
    // as the discovery listener itself depends on components that need to be discovered.
    public List discoverComponents( ClassRealm classRealm )
        throws PlexusConfigurationException, ComponentRepositoryException
    {
        return discoverComponents( classRealm, false );
    }

    /**
     * @see org.codehaus.plexus.MutablePlexusContainer#discoverComponents(org.codehaus.plexus.classworlds.realm.ClassRealm,boolean)
     */
    public List discoverComponents( ClassRealm classRealm, boolean override )
        throws PlexusConfigurationException, ComponentRepositoryException
    {
        return ComponentDiscoveryPhase.discoverComponents( this, classRealm, override );
    }

    protected void start()
        throws PlexusContainerException
    {
        // XXX this is called after initializeConfiguration - is this correct?
        configuration = null;
    }

    public void dispose()
    {
        disposeAllComponents();

        boolean needToDisposeRealm = true;

        if ( parentContainer != null && containerRealm.getId().equals( parentContainer.getContainerRealm().getId() ) )
        {
            needToDisposeRealm = false;
        }

        if ( parentContainer != null )
        {
            parentContainer.removeChildContainer( getName() );

            parentContainer = null;
        }

        try
        {
            containerRealm.setParentRealm( null );

            if ( needToDisposeRealm )
            {
                classWorld.disposeRealm( containerRealm.getId() );
            }
        }
        catch ( NoSuchRealmException e )
        {
            getLogger().debug( "Failed to dispose realm for exiting container: " + getName(), e );
        }
    }

    protected void disposeAllComponents()
    {
        // copy the list so we don't get concurrent modification exceptions during disposal
        Collection collection = new ArrayList( componentManagerManager.getComponentManagers().values() );
        for ( Iterator iter = collection.iterator(); iter.hasNext(); )
        {
            try
            {
                ( (ComponentManager) iter.next() ).dispose();
            }
            catch ( Exception e )
            {
                getLogger().error( "Error while disposing component manager. Continuing with the rest", e );
            }
        }

        componentManagerManager.getComponentManagers().clear();
    }

    public void addContextValue( Object key, Object value )
    {
        containerContext.put( key, value );
    }

    // ----------------------------------------------------------------------
    // Misc Configuration
    // ----------------------------------------------------------------------

    public String getName()
    {
        return name;
    }

    public ClassWorld getClassWorld()
    {
        return classWorld;
    }

    public void setClassWorld( ClassWorld classWorld )
    {
        this.classWorld = classWorld;
    }

    public ClassRealm getContainerRealm()
    {
        return containerRealm;
    }

    public void setContainerRealm( ClassRealm containerRealm )
    {
        this.containerRealm = containerRealm;
    }

    // ----------------------------------------------------------------------
    // Context
    // ----------------------------------------------------------------------

    public Context getContext()
    {
        return containerContext;
    }

    // ----------------------------------------------------------------------
    // Configuration
    // ----------------------------------------------------------------------

    // TODO: put this in a separate helper class and turn into a component if possible, too big.

    protected void initializeConfiguration()
        throws ConfigurationProcessingException, ConfigurationResourceNotFoundException, PlexusConfigurationException,
        ContextException, IOException
    {
        // System userConfiguration

        InputStream is = containerRealm.getResourceAsStream( PlexusConstants.BOOTSTRAP_CONFIGURATION );

        if ( is == null )
        {
            ClassRealm cr = containerRealm;
            String realmStack = "";
            while ( cr != null )
            {
                realmStack += "\n  " + cr.getId() + " parent=" + cr.getParent() + " ("
                    + cr.getResource( PlexusConstants.BOOTSTRAP_CONFIGURATION ) + ")";
                cr = cr.getParentRealm();
            }

            throw new IllegalStateException( "The internal default plexus-bootstrap.xml is missing. "
                + "This is highly irregular, your plexus JAR is most likely corrupt. Realms:" + realmStack );
        }

        PlexusConfiguration bootstrapConfiguration = PlexusTools
            .buildConfiguration( PlexusConstants.BOOTSTRAP_CONFIGURATION, ReaderFactory.newXmlReader( is ) );

        // Some of this could probably be collapsed as having a plexus.xml in your
        // META-INF/plexus directory is probably a better solution then specifying
        // a configuration with an URL but I'm leaving the configuration by URL
        // as folks might be using it ... I made this change to accomodate Maven
        // but I think it's better to discover a configuration in a standard
        // place.

        configuration = bootstrapConfiguration;

        if ( !containerContext.contains( PlexusConstants.IGNORE_CONTAINER_CONFIGURATION )
            || containerContext.get( PlexusConstants.IGNORE_CONTAINER_CONFIGURATION ) != Boolean.TRUE )
        {
            PlexusXmlComponentDiscoverer discoverer = new PlexusXmlComponentDiscoverer();

            PlexusConfiguration plexusConfiguration = discoverer.discoverConfiguration( getContext(), containerRealm );

            if ( plexusConfiguration != null )
            {
                configuration = PlexusConfigurationMerger.merge( plexusConfiguration, configuration );

                processConfigurationsDirectory();
            }
        }

        if ( configurationReader != null )
        {
            // User userConfiguration

            PlexusConfiguration userConfiguration = PlexusTools
                .buildConfiguration( "<User Specified Configuration Reader>",
                    getInterpolationConfigurationReader( configurationReader ) );

            // Merger of bootstrapConfiguration and user userConfiguration

            configuration = PlexusConfigurationMerger.merge( userConfiguration, configuration );

            processConfigurationsDirectory();
        }

        // ---------------------------------------------------------------------------
        // Now that we have the configuration we will use the ConfigurationProcessor
        // to inline any external configuration instructions.
        //
        // At his point the variables in the configuration have already been
        // interpolated so we can send in an empty Map because the containerContext
        // values are already there.
        // ---------------------------------------------------------------------------

        ConfigurationProcessor p = new ConfigurationProcessor();

        p.addConfigurationResourceHandler( new FileConfigurationResourceHandler() );

        p.addConfigurationResourceHandler( new DirectoryConfigurationResourceHandler() );

        configuration = p.process( configuration, Collections.EMPTY_MAP );
    }

    protected Reader getInterpolationConfigurationReader( Reader reader )
    {
        return new InterpolationFilterReader( reader, new ContextMapAdapter( containerContext ) );
    }

    /**
     * Process any additional component configuration files that have been specified. The specified directory is scanned
     * recursively so configurations can be within nested directories to help with component organization.
     */
    private void processConfigurationsDirectory()
        throws PlexusConfigurationException
    {
        String s = configuration.getChild( "configurations-directory" ).getValue( null );

        if ( s != null )
        {
            PlexusConfiguration componentsConfiguration = configuration.getChild( "components" );

            File configurationsDirectory = new File( s );

            if ( configurationsDirectory.exists() && configurationsDirectory.isDirectory() )
            {
                List componentConfigurationFiles;
                try
                {
                    componentConfigurationFiles = FileUtils.getFiles( configurationsDirectory, "**/*.conf", "**/*.xml" );
                }
                catch ( IOException e )
                {
                    throw new PlexusConfigurationException( "Unable to locate configuration files", e );
                }

                for ( Iterator i = componentConfigurationFiles.iterator(); i.hasNext(); )
                {
                    File componentConfigurationFile = (File) i.next();

                    Reader reader = null;
                    try
                    {
                        reader = ReaderFactory.newXmlReader( componentConfigurationFile );
                        PlexusConfiguration componentConfiguration = PlexusTools
                            .buildConfiguration( componentConfigurationFile.getAbsolutePath(),
                                getInterpolationConfigurationReader( reader ) );

                        componentsConfiguration.addChild( componentConfiguration.getChild( "components" ) );
                    }
                    catch ( FileNotFoundException e )
                    {
                        throw new PlexusConfigurationException( "File " + componentConfigurationFile
                            + " disappeared before processing", e );
                    }
                    catch ( IOException e )
                    {
                        throw new PlexusConfigurationException( "IO error while reading " + componentConfigurationFile, e );
                    }
                    finally
                    {
                        IOUtil.close( reader );
                    }
                }
            }
        }
    }

    public void addJarResource( File jar )
        throws PlexusContainerException
    {
        try
        {
            containerRealm.addURL( jar.toURI().toURL() );

            if ( this.initialized )
            {
                discoverComponents( containerRealm );
            }
        }
        catch ( MalformedURLException e )
        {
            throw new PlexusContainerException( "Cannot add jar resource: " + jar + " (bad URL)", e );
        }
        catch ( PlexusConfigurationException e )
        {
            throw new PlexusContainerException( "Cannot add jar resource: " + jar
                + " (error discovering new components)", e );
        }
        catch ( ComponentRepositoryException e )
        {
            throw new PlexusContainerException( "Cannot add jar resource: " + jar
                + " (error discovering new components)", e );
        }
    }

    public void addJarRepository( File repository )
    {
        if ( repository.exists() && repository.isDirectory() )
        {
            File[] jars = repository.listFiles();

            for ( int j = 0; j < jars.length; j++ )
            {
                if ( jars[j].getAbsolutePath().endsWith( ".jar" ) )
                {
                    try
                    {
                        addJarResource( jars[j] );
                    }
                    catch ( PlexusContainerException e )
                    {
                        getLogger().warn( "Unable to add JAR: " + jars[j], e );
                    }
                }
            }
        }
        else
        {
            String message = "The specified JAR repository doesn't exist or is not a directory: '"
                + repository.getAbsolutePath() + "'.";

            if ( getLogger() != null )
            {
                getLogger().warn( message );
            }
            else
            {
                System.out.println( message );
            }
        }
    }

    public Logger getLogger()
    {
        return super.getLogger();
    }

    // ----------------------------------------------------------------------
    // Discovery
    // ----------------------------------------------------------------------

    public void registerComponentDiscoveryListener( ComponentDiscoveryListener listener )
    {
        componentDiscovererManager.registerComponentDiscoveryListener( listener );
    }

    public void removeComponentDiscoveryListener( ComponentDiscoveryListener listener )
    {
        componentDiscovererManager.removeComponentDiscoveryListener( listener );
    }

    // ----------------------------------------------------------------------
    // Autowire Support
    // ----------------------------------------------------------------------

    // note:jvz Currently this only works for setters as I'm experimenting for
    // webwork. I would like the API for autowiring to be simple so we could easily look
    // for constructors with parameters and use that method of composition before attempting
    // the use of setters or private fields.

    public Object autowire( Object component )
        throws CompositionException
    {
        SetterComponentComposer composer = new SetterComponentComposer();

        composer.assembleComponent( component, null, this );

        return component;
    }

    public Object createAndAutowire( String clazz )
        throws CompositionException, ClassNotFoundException, InstantiationException, IllegalAccessException
    {
        Object component = containerRealm.loadClass( clazz ).newInstance();

        SetterComponentComposer composer = new SetterComponentComposer();

        composer.assembleComponent( component, null, this );

        return component;
    }

    // ----------------------------------------------------------------------
    // Reloading
    // ----------------------------------------------------------------------

    public void setReloadingEnabled( boolean reloadingEnabled )
    {
        this.reloadingEnabled = reloadingEnabled;
    }

    public boolean isReloadingEnabled()
    {
        return reloadingEnabled;
    }

    // ----------------------------------------------------------------------------
    // Mutable Container Interface
    // ----------------------------------------------------------------------------

    public ComponentRepository getComponentRepository()
    {
        return componentRepository;
    }

    public void setComponentRepository( ComponentRepository componentRepository )
    {
        this.componentRepository = componentRepository;
    }

    public ComponentManagerManager getComponentManagerManager()
    {
        return componentManagerManager;
    }

    public void setComponentManagerManager( ComponentManagerManager componentManagerManager )
    {
        this.componentManagerManager = componentManagerManager;
    }

    public LifecycleHandlerManager getLifecycleHandlerManager()
    {
        return lifecycleHandlerManager;
    }

    public void setLifecycleHandlerManager( LifecycleHandlerManager lifecycleHandlerManager )
    {
        this.lifecycleHandlerManager = lifecycleHandlerManager;
    }

    public ComponentDiscovererManager getComponentDiscovererManager()
    {
        return componentDiscovererManager;
    }

    public void setComponentDiscovererManager( ComponentDiscovererManager componentDiscovererManager )
    {
        this.componentDiscovererManager = componentDiscovererManager;
    }

    public ComponentFactoryManager getComponentFactoryManager()
    {
        return componentFactoryManager;
    }

    public void setComponentFactoryManager( ComponentFactoryManager componentFactoryManager )
    {
        this.componentFactoryManager = componentFactoryManager;
    }

    public ComponentLookupManager getComponentLookupManager()
    {
        return componentLookupManager;
    }

    public void setComponentLookupManager( ComponentLookupManager componentLookupManager )
    {
        this.componentLookupManager = componentLookupManager;
    }

    public ComponentComposerManager getComponentComposerManager()
    {
        return componentComposerManager;
    }

    public void setComponentComposerManager( ComponentComposerManager componentComposerManager )
    {
        this.componentComposerManager = componentComposerManager;
    }

    public LoggerManager getLoggerManager()
    {
        return loggerManager;
    }

    public void setLoggerManager( LoggerManager loggerManager )
    {
        this.loggerManager = loggerManager;
    }

    // Configuration

    public PlexusConfiguration getConfiguration()
    {
        return configuration;
    }

    public void setConfiguration( PlexusConfiguration configuration )
    {
        this.configuration = configuration;
    }

    // Parent Container

    public PlexusContainer getParentContainer()
    {
        return parentContainer;
    }

    // ----------------------------------------------------------------------------
    // Component Realms
    // ----------------------------------------------------------------------------

    public ClassRealm getComponentRealm( String realmId )
    {
        ClassRealm realm = null;

        try
        {
            realm = classWorld.getRealm( realmId );
        }
        catch ( NoSuchRealmException e )
        {
            // This should never happen: when a component is discovered, it is discovered from a realm and
            // it is at that point the realm id is assigned to the component descriptor.
        }

        if ( realm == null )
        {
            // The core components need the container realm.
            realm = containerRealm;
        }

        return realm;
    }

    private InputStream toStream( String resource )
        throws PlexusContainerException
    {
        if ( resource == null )
        {
            return null;
        }

        InputStream is = getClass().getClassLoader().getResourceAsStream( resource );

        if ( is == null )
        {
            try
            {
                return new FileInputStream( resource );
            }
            catch ( FileNotFoundException e )
            {
                return null;
            }
        }

        return is;
    }


    /**
     * Utility method to get a default lookup realm for a component.
     */
    public ClassRealm getLookupRealm( Object component )
    {
        if ( component.getClass().getClassLoader() instanceof ClassRealm )
        {
            return ( (ClassRealm) component.getClass().getClassLoader() );
        }
        else
        {
            return getLookupRealm();
        }

    }
}
TOP

Related Classes of org.codehaus.plexus.DefaultPlexusContainer

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.