dion        2003/08/18 21:28:50

  Modified:    src/java/org/apache/maven/plugin PluginManager.java
  Added:       src/java/org/apache/maven/plugin PluginCacheManager.java
  Removed:     src/java/org/apache/maven/plugin JellyScriptHousing.java
                        GoalToJellyScriptHousingMapper.java
                        JellyPlugin.java
  Log:
  Switch stable branch back to HEAD
  
  Revision  Changes    Path
  1.63      +655 -518  maven/src/java/org/apache/maven/plugin/PluginManager.java
  
  Index: PluginManager.java
  ===================================================================
  RCS file: /home/cvs/maven/src/java/org/apache/maven/plugin/PluginManager.java,v
  retrieving revision 1.62
  retrieving revision 1.63
  diff -u -r1.62 -r1.63
  --- PluginManager.java        4 Aug 2003 06:27:56 -0000       1.62
  +++ PluginManager.java        19 Aug 2003 04:28:50 -0000      1.63
  @@ -57,51 +57,67 @@
    */
   
   import com.werken.forehead.Forehead;
  -import com.werken.forehead.ForeheadClassLoader;
   import com.werken.werkz.Goal;
   import com.werken.werkz.Session;
  -import com.werken.werkz.WerkzProject;
   import com.werken.werkz.jelly.JellySession;
  -import org.apache.commons.grant.GrantProject;
  -import org.apache.commons.jelly.Script;
  -import org.apache.commons.jelly.XMLOutput;
  -import org.apache.commons.jelly.tags.ant.AntTagLibrary;
  +import org.apache.commons.io.FileUtils;
  +import org.apache.commons.lang.StringUtils;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   import org.apache.maven.AbstractMavenComponent;
   import org.apache.maven.GoalException;
  -import org.apache.maven.Maven;
   import org.apache.maven.MavenConstants;
   import org.apache.maven.MavenException;
  -import org.apache.maven.jelly.JellyBuildListener;
  -import org.apache.maven.jelly.JellyPropsHandler;
  +import org.apache.maven.MavenSession;
  +import org.apache.maven.MavenUtils;
  +import org.apache.maven.NoGoalException;
  +import org.apache.maven.UnknownGoalException;
   import org.apache.maven.jelly.JellyUtils;
   import org.apache.maven.jelly.MavenJellyContext;
  -import org.apache.maven.jelly.tags.werkz.MavenAttainGoalListener;
  -import org.apache.maven.project.Dependency;
   import org.apache.maven.project.Project;
  -import org.apache.maven.repository.Artifact;
   import org.apache.maven.util.Expand;
  -import org.apache.tools.ant.types.Path;
   
   import java.io.File;
   import java.io.FileInputStream;
  -import java.io.FileReader;
  -import java.io.InputStream;
  -import java.io.OutputStreamWriter;
  -import java.io.PrintStream;
  -import java.io.Writer;
  -import java.net.MalformedURLException;
  -import java.net.URL;
  -import java.util.HashMap;
  +import java.io.IOException;
  +import java.util.ArrayList;
  +import java.util.Collections;
  +import java.util.HashSet;
   import java.util.Iterator;
  +import java.util.LinkedList;
   import java.util.List;
  -import java.util.Map;
  +import java.util.Properties;
   import java.util.Set;
   import java.util.StringTokenizer;
   
  +/*
  +
  +NOTES:
  +
  +We initialize the plugin with an empty context. When we are finished initializing 
the
  +plugins we will have a context with a werkz project object that has been created
  +that will contain all the goals present within the plugins.
  +
  +The result of this initialization is the creation of all the cache files which
  +give us an outline of what is required to attain a particular goal.
  +
  +When a particular project needs to attain one of these goals we need to
  +load the plugin and in doing so we run the plugin.jelly script for the required
  +plugins against the projects context.
  +
  +Possibly eventually we could make this more efficient storing the plugin.jelly
  +in an accessible templated form which when required for a particular project
  +can be executed against the project's context.
  +
  +IMPLEMENTATION NOTES
  +
  +- We need to know the goals to attain
  +- We need to keep track of plugins that have been loaded for a particular project.
  +
  +*/
  +
   /**
  - * Plugin manager for Maven. <p>
  + * Plugin manager for MavenSession. <p>
    *
    * The <code>PluginManager</code> deals with all aspects of a plugins lifecycle.
    * </p>
  @@ -111,27 +127,24 @@
    *
    * @version $Id$
    *
  - * @todo Goal inheritance
    */
   public class PluginManager
       extends AbstractMavenComponent
   {
  +    /** Plug-in main script name. */
  +    public static final String PLUGIN_SCRIPT_NAME = "plugin.jelly";
  +
  +    /** Plug-in default properties name. */
  +    public static final String PLUGIN_PROPERTIES_NAME = "plugin.properties";
  +
       /** Logger */
       private static final Log log = LogFactory.getLog( PluginManager.class );
  -    /** */
  -    public static final String PLUGIN_MANAGER = "maven.pluginManager";
  -    /** */
  -    public static final String BASE_CONTEXT = "maven.goalAttainmentContext";
  -    /** */
  -    public static String JELLY_CONTEXT = "mavenGoalTag.jellyContext";
  -    /** */
  -    public static String XML_OUTPUT = "mavenGoalTag.xmlOutput";
   
       /**
        * The variable key that holds an implementation of the
  -     * <code>com.werken.werkz.Session</code> in the parent scope pluginContext.
  +     * <code>com.werken.werkz.Session</code> in the parent scope context.
        */
  -    public static final String GLOBAL_SESSION_KEY = "maven.session.global";
  +    private static final String GLOBAL_SESSION_KEY = "maven.session.global";
   
       /** The directory where plugin jars reside under Maven's home. */
       private File pluginsDir;
  @@ -139,31 +152,23 @@
       /** The directory where the plugin jars are unpacked to. */
       private File unpackedPluginsDir;
   
  +    /**
  +     * This contains a set of sets where each set contains a list of
  +     * plugins that have been loaded for a particular project.
  +     */
  +    private Set loadedPlugins;
  +
       /** Is the plugin manager initialized. */
       private boolean initialized = false;
   
       /** Maven session reference. */
  -    private Maven maven;
  -
  -    private Map jellyScriptHousings;
  -    
  -    /** map of loaded plugins by id */
  -    private Map loadedPlugins;
  -    
  -    /** map of plugins by id */
  -    private Map plugins;
  -
  -    /** rootClassLoader classloader. */
  -    private ForeheadClassLoader rootClassLoader;
  +    private MavenSession mavenSession;
   
  -    /** maven.rootClassLoader classloader. */
  -    private ForeheadClassLoader mavenRootClassLoader;
  +    /** Plugin cache manager. */
  +    private PluginCacheManager cacheManager;
   
  -    /** Goal to Plugins mapper. */
  -    private GoalToJellyScriptHousingMapper mapper;
  -
  -    /** Context in which to compile Jelly scripts. */
  -    private MavenJellyContext compileScriptContext;
  +    /** Cache manager for user jelly scripts. */
  +    private PluginCacheManager transientCacheManager;
   
       /**
        *  Default constructor.
  @@ -171,150 +176,50 @@
        *  @param mavenSession The MavenSession this plugin manager will use
        *         until Maven shuts down.
        */
  -    public PluginManager( Maven mavenSession )
  +    public PluginManager( MavenSession mavenSession )
       {
  -        this.maven = mavenSession;
  -
  -        jellyScriptHousings = new HashMap();
  -        loadedPlugins = new HashMap();
  -        plugins = new HashMap();
  -
  -        mapper = new GoalToJellyScriptHousingMapper();
  +        this.mavenSession = mavenSession;
   
  -        // FIXME: Why are there two hard coded class loaders?
  -        rootClassLoader = Forehead.getInstance().getClassLoader( "root" );
  -        mavenRootClassLoader = Forehead.getInstance().getClassLoader( "root.maven" 
);
  -
  -        compileScriptContext = new MavenJellyContext();
  +        loadedPlugins = new HashSet();
  +        cacheManager = new PluginCacheManager( true );
  +        transientCacheManager = new PluginCacheManager( true );
       }
   
       // ----------------------------------------------------------------------
  -    // Accessors
  +    // A C C E S S O R S
       // ----------------------------------------------------------------------
   
  -    private Maven getMaven()
  -    {
  -        return maven;
  -    }
  -
  -    private void setMaven( Maven maven )
  -    {
  -        this.maven = maven;
  -    }
  -
  -    /**
  -     * Expand the plugin jars if needed
  -     * @throws MavenException
  -     */
  -    private void expandPlugins() throws MavenException
  -    {
  -        File[] files = getPluginsDir().listFiles();
  -        
  -        // First we expand any JARs that contain plugins to the unpack directory.
  -        // This will be a different directory than the plugin jars if
  -        // MAVEN_HOME_LOCAL / maven.home.local was set to a different directory
  -        // than MAVEN_HOME / maven.home.
  -        Expand unzipper = new Expand();
  -        for ( int i = 0; i < files.length; ++i )
  -        {
  -            processPluginFile(unzipper, files[i]);
  -        }
  -    }
  -
       /**
  -     * Load all plugins in the unpacked plugins dir 
  -     * @throws Exception
  +     *  Retrieve the set of all goal names.
  +     *
  +     *  @return The set of <code>String</code> goal names.
        */
  -    private void loadPlugins() throws Exception
  -    {
  -        File[] files = getUnpackedPluginsDir().listFiles();
  -
  -        // Process each of the directorties.
  -        for ( int i = 0; i < files.length; ++i )
  -        {
  -            if ( files[i].isDirectory() )
  -            {
  -                String pluginId = files[i].getName();
  -                if ( !isLoaded( pluginId ) )
  -                {
  -                    loadPlugin( pluginId );
  -                }
  -            }
  -        }
  -    }
  -
  -    private void processPluginFile(Expand unzipper, File pluginFile)
  -        throws MavenException
  +    public Set getGoalNames()
       {
  -        // Only unpack the JAR if it hasn't been already, or is newer
  -        // than the plugin directory
  -        if ( pluginFile.getName().endsWith( ".jar" ) )
  -        {
  -            // this is where JellyPlugins should be determined and created
  -            JellyPlugin plugin = new JellyPlugin();
  -            plugin.setJarFile( pluginFile );
  -            String directory = pluginFile.getName();
  -            directory = directory.substring( 0, directory.indexOf( ".jar" ) );
  -            plugin.setId( directory );
  -            plugin.setUnpackDirectory( getUnpackedPluginsDir() );
  -            plugin.unpack();
  -            plugins.put(plugin.getId(), plugin);
  -        }
  +        return cacheManager.getGoalCache().keySet();
       }
   
       /**
  -     *  Load the specified plugin.
  +     *  Retrieve a goal description by the goal name.
        *
  -     *  @param name The name of the plugin to load.
  +     *  @param name The goal name.
        *
  -     *  @throws Exception If an error occurs while initializing the plugin.
  +     *  @return The description or <code>null</code> if no
  +     *          description has been set.
        */
  -    private void loadPlugin( String name )
  -        throws Exception
  +    public String getGoalDescription( String name )
       {
  -        System.err.println( "Loading plugin '" + name + "'" );
  -        JellyPlugin plugin = (JellyPlugin)plugins.get(name);
  -        if (plugin == null)
  -        {
  -            plugin = new JellyPlugin();
  -            plugin.setId(name);
  -        }
  -        
  -        plugin.setUnpackDirectory( getUnpackedPluginsDir() );
  -        plugin.setParentClassLoader( mavenRootClassLoader );
  -        Project pluginProject = getMaven().getProject( plugin.getDescriptor() , 
false );
  -        plugin.setProject( pluginProject );
  -        plugin.processDependencies();
  +        String value = cacheManager.getGoalCache().getProperty( name );
   
  -        if ( plugin.hasScript() )
  +        // Must check for "null" in case it was loaded from cache that way
  +        if ( value == null || value.startsWith("null>"))
           {
  -            JellyScriptHousing jellyScriptHousing = null;
  -            try
  -            {
  -                // Create the PluginHousing
  -                jellyScriptHousing = createJellyScriptHousing( plugin );
  -            }
  -            catch ( Exception e )
  -            {
  -                System.err.println( "Error loading plugin '" + name + "'" );
  -                throw e;
  -            }
  -    
  -            // Store the plugin housing for future use.
  -            jellyScriptHousings.put( name, jellyScriptHousing );
  -            mapper.parse( new FileReader( plugin.getScriptFile() ), 
jellyScriptHousing );
  +            return null;
           }
  -        loadedPlugins.put(plugin.getId(), plugin);
   
  -    }
  +        String description = value.substring( 0, value.indexOf( ">" ) );
   
  -    /**
  -     * @todo Why is this method public?
  -     * @return
  -     */
  -    public GoalToJellyScriptHousingMapper getMapper()
  -    {
  -        return mapper;
  +        return description;
       }
   
       // ----------------------------------------------------------------------
  @@ -325,7 +230,6 @@
        *  Initialize all plugins.
        *
        *  @throws Exception If an error occurs while initializing any plugin.
  -     * @todo why is this method public?
        */
       public void initialize()
           throws Exception
  @@ -335,487 +239,646 @@
               return;
           }
   
  -        setPluginsDir( new File( getMaven().getProperty( MavenConstants.MAVEN_HOME 
), "plugins" ) );
  -        setUnpackedPluginsDir( new File( maven.getProperty( 
MavenConstants.MAVEN_UNPACKED_PLUGINS_DIR ) ) );
  +        if( log.isDebugEnabled() )
  +        {
  +           log.debug( "Initializing Plugins!" );
  +        }
  +        setPluginsDir( new File( mavenSession.getRootContext().getMavenHome(), 
"plugins" ) );
  +        setUnpackedPluginsDir( new File( 
mavenSession.getRootContext().getUnpackedPluginsDir() ) );
  +        if( log.isDebugEnabled() )
  +        {
  +            log.debug( "Set plugin source directory to "
  +                + getPluginsDir().getAbsolutePath() );
  +            log.debug( "Set plugin cache directory to "
  +                + getUnpackedPluginsDir().getAbsolutePath() );
  +        }
  +        cacheManager.loadCache();
  +
  +        if( log.isDebugEnabled() )
  +        {
  +            log.debug( "Unpacking plugins from directory --> "
  +                + getPluginsDir().getAbsolutePath() );
  +        }
   
  -        expandPlugins();
  +        expandPluginJars();
   
  -        loadPlugins();
  +        cachePlugins();
   
           initialized = true;
   
  -        log.info( "Finished initializing Plugins!" );
  +        log.debug( "Finished initializing Plugins!" );
       }
   
       /**
  +     * For any plugin that is not already cached according to the cache manager
  +     * we cache it.
  +     * @throws Exception FIXME. When anything goes wrong
  +     */
  +    private void cachePlugins() throws Exception
  +    {
  +        // We need to get the directory listing again so that we
  +        // can process plugins that were just unpacked by the
  +        // above process. This time we're looking at the unpacked plugins.
  +        File[] files = getUnpackedPluginsDir().listFiles();
  +        
  +        if (log.isDebugEnabled())
  +        {
  +            log.debug( "Processing unpacked plugins in "
  +                + getUnpackedPluginsDir().getAbsolutePath() );
  +        }
  +        
  +        // Process each of the directorties.
  +        for ( int i = 0; i < files.length; ++i )
  +        {
  +            if ( files[i].isDirectory() )
  +            {
  +                String directory = files[i].getName();
  +        
  +                // If we haven't cached (or previous cache data has become invalid)
  +                // the plugin, then do so now.
  +                if ( isCached( directory ) == false )
  +                {
  +                    try
  +                    {
  +                        cachePlugin( files[i].getName() );
  +                    }
  +                    catch ( Exception e )
  +                    {
  +                        log.error( getMessage( "plugin.loading.error", 
files[i].getName() ) );
  +                        e.printStackTrace();
  +                    }
  +                }
  +            }
  +        }
  +        
  +        saveCache();
  +    }
  +
  +    /**
  +     * Expand the plugin jars if needed
  +     * @throws MavenException
  +     */
  +    private void expandPluginJars() throws MavenException
  +    {
  +        File[] files = getPluginsDir().listFiles();
  +
  +        // First we expand any JARs that contain plugins to the unpack directory.
  +        // This will be a different directory than the plugin jars
  +        // MAVEN_HOME_LOCAL / maven.home.local was set to a different directory
  +        // than MAVEN_HOME / maven.home.
  +        for ( int i = 0; i < files.length; ++i )
  +        {
  +            // Only unpack the JAR if it hasn't been already, or is newer
  +            // than the plugin directory
  +            if ( files[i].getName().endsWith( ".jar" ) )
  +            {
  +                String directory = files[i].getName();
  +                directory = directory.substring( 0, directory.indexOf( ".jar" ) );
  +                File unzipDir = new File( getUnpackedPluginsDir(), directory );
  +
  +                // if there's no directory, or the jar is newer, expand the jar
  +                if (   unzipDir.exists() == false
  +                    || files[i].lastModified() > unzipDir.lastModified() )
  +                {
  +                    if( log.isDebugEnabled() )
  +                    {
  +                        log.debug( "Unpacking '" + directory
  +                            + "' plugin to directory --> "
  +                            + unzipDir.getAbsolutePath() );
  +                    }
  +                    invalidateCache( directory );
  +
  +                    File processed = getPluginProcessedMarker( unzipDir.getName() );
  +                    if ( processed.exists() )
  +                    {
  +                        processed.delete();
  +                    }
  +
  +                    try
  +                    {
  +                        Expand unzipper = new Expand();
  +                        unzipper.setSrc( files[i] );
  +                        unzipper.setDest( unzipDir );
  +                        unzipper.execute();
  +                    }
  +                    catch (IOException e)
  +                    {
  +                        throw new MavenException("Unable to extract plugin: " + 
files[i], e);
  +                    }
  +                }
  +            }
  +        }
  +    }
  +
  +
  +    /**
        *  Attain the goals.
        *
        *  @throws org.apache.maven.UnknownGoalException If one of the specified
        *          goals refers to an non-existent goal.
        *  @throws Exception If an exception occurs while running a goal.
        */
  -    public void attainGoals( Project project, List goals )
  +    public void attainGoals( Project project )
           throws GoalException, Exception
       {
  -        MavenJellyContext baseContext = createBaseContext( project );
  -
           // Before attempting to attain the goals verify the project
           // if desired.
  -        // FIXME: From attainGoals angle, how does it know the project needs to
  -        //        to be verified, or that the project object hasn't been used before
           project.verifyDependencies();
  +        project.processDependencies();
   
  -        // Set up the ant project.
  -        buildAntProject( project, baseContext );
  -
  -        Session session = getJellySession(baseContext);
  -        // add the global session to the pluginContext so that it can be used by 
tags
  -        baseContext.setVariable( GLOBAL_SESSION_KEY, session );
  -
  -        WerkzProject werkzProject = buildWerkzProject( baseContext );
  -
  -        // 
-------------------------------------------------------------------------------------------------------------
  -        // Execution of the Jelly scripts:
  -        //
  -        // We run the Jelly scripts in the following order:
  -        //
  -        // 1) driver.jelly - doesn't exist anymore
  -        // 2) project's maven.xml
  -        // 3) parent's maven.xml (if it exists)
  -        // 4) plugin.jelly
  -        //
  -        // The Maven version of the <goal/> Werkz tag has been constructed so that 
the first
  -        // definition of a goal wins.
  -        //
  -        // We run them in this order because we do not know before hand which 
plugin goals a project
  -        // may wish to override so we guarantee precedence of the goals by running 
the jelly scripts
  -        // in the above mentioned order.
  -        // 
-------------------------------------------------------------------------------------------------------------
  -
  -        // driver.jelly
  -        //InputStream driver = 
PluginManager.class.getClassLoader().getResourceAsStream( "driver.jelly" );
  -        //JellyScriptHousing driverHousing = createJellyScriptHousing( project, 
null, driver );
  -        //driverHousing.setSource( "driver.jelly" );
  -        //mapper.parse( new InputStreamReader( driver ), driverHousing );
  -        //runJellyScriptHousing( driverHousing, baseContext );
  -
  -        // FIXME: Part of this belongs as a method on Project, e.g. the name and
  -        //        construction of maven.xml
  -        // Project's Jelly script
  -        if ( project.hasMavenXml() )
  -        {
  -            File mavenXml = project.getMavenXml();
  -            //!!! This is the cause of the classloader problems!!
  -            JellyScriptHousing jellyScriptHousing = createJellyScriptHousing( 
project, null, mavenXml );
  -            mapper.parse( new FileReader( mavenXml ), jellyScriptHousing );
  -            runJellyScriptHousing( jellyScriptHousing, baseContext );
  -        }
  -
  -        // Parent's Jelly script
  -        // FIXME: What about further up the chain?
  -        if ( project.hasParent() && project.getParent().hasMavenXml() )
  +        // If this project has a parent then we will load it's maven.xml
  +        // file into this project so any goals the parent specifies in
  +        // its maven.xml file are available to the child. We load this
  +        // before the child's maven.xml so that the child can override
  +        // any desired goals.
  +        if ( project.hasParent() )
           {
  -            // FIXME: this is a badly named method
  -            File f = project.parentMavenXml();
  +            project.loadJellyScript( project.parentMavenXml() );
  +        }
   
  -            if ( f.exists() )
  -            {
  -                JellyScriptHousing jellyScriptHousing = createJellyScriptHousing( 
project, null, f );
  -                mapper.parse( new FileReader( f ), jellyScriptHousing );
  -                runJellyScriptHousing( jellyScriptHousing, baseContext );
  -            }
  +        // Currently we will not attempt to load a maven.xml file when the 
project.xml
  +        // file is not present.
  +        if ( project.getFile() != null )
  +        {
  +            File mavenXmlFile = new File( project.getFile().getParentFile(),
  +                                          MavenConstants.BUILD_FILE_NAME );
  +            loadJellyScript( mavenXmlFile, project );
           }
   
  -        // ----------------------------------------------------------------------
  -        // Default goal handling
  -        // ----------------------------------------------------------------------
  +        // There will always be at least one goal present which is the build:start
  +        // goal. If this is the only goal present then we want to add either the
  +        // default goal specified in the project.xml file, or the default goal
  +        // specified in the driver.properties file.
   
  -        if ( goals.size() == 0 )
  +        //if ( goalNames.size() == 1 )
  +        if ( project.getGoalNames().size() == 0)
           {
  -            String defaultGoalName = mapper.getDefaultGoalName();
  -
  -            if ( defaultGoalName != null )
  +            if (project.getContext().getWerkzProject() == null)
               {
  -                goals.add( defaultGoalName );
  +                throw new NoGoalException("No goal specified and no project.xml 
found.");
  +            }
  +            else
  +            {
  +                String defaultGoalName = 
project.getContext().getWerkzProject().getDefaultGoalName();
  +
  +                if ( defaultGoalName != null )
  +                {
  +                    project.getGoalNames().add( defaultGoalName );
  +                }
               }
           }
   
  -        // Plugin Jelly scripts
  -        for ( Iterator i = goals.iterator(); i.hasNext(); )
  +        //project.getGoalNames().add( BUILD_END_GOAL );
  +
  +        for ( Iterator i = project.getGoalNames().iterator(); i.hasNext(); )
           {
               String goalName = (String) i.next();
  +            prepForGoal( goalName, project );
  +            Goal eachGoal = project.getContext().getWerkzProject().getGoal( 
goalName );
   
  -            // Now at this point we should be able to use the name of a goal to 
lookup all
  -            // the plugins (that are stored in the plugin housings) that need to be 
executed
  -            // in order to satisfy all the required preconditions for successful 
goal attainment.
  -
  -            Set plugins = mapper.resolveJellyScriptHousings( goalName );
  -
  -            for ( Iterator j = plugins.iterator(); j.hasNext(); )
  +            if ( eachGoal == null )
               {
  -                JellyScriptHousing jellyScriptHousing = (JellyScriptHousing) 
j.next();
  +                throw new UnknownGoalException( goalName );
  +            }
  +        }
   
  +        Session session = new JellySession( project.getContext().getXMLOutput() );
  +        Thread.currentThread().setContextClassLoader( null );
   
  -                //!!! Not sure why the housing is null.
  -                if ( jellyScriptHousing != null )
  -                {
  -                    runJellyScriptHousing( jellyScriptHousing, baseContext );
  -                }
  -            }
  +        // add the global session to the context so that it can be used by tags
  +        project.getContext().setVariable(GLOBAL_SESSION_KEY, session);
   
  -            Goal goal = baseContext.getWerkzProject().getGoal( goalName );
  -            goal.attain( session );
  +        for ( Iterator i = project.getGoalNames().iterator(); i.hasNext(); )
  +        {
  +            String eachGoalName = (String) i.next();
  +            Goal eachGoal = project.getContext().getWerkzProject().getGoal( 
eachGoalName );
  +            eachGoal.attain( session );
           }
       }
   
       /**
  -     * 
  -     * @param context the base context for the werkz project
  -     * @return a configured werkz project
  -     */
  -    private WerkzProject buildWerkzProject(MavenJellyContext context)
  -    {
  -        // We put in our listener to frob the session.
  -        MavenAttainGoalListener listener = new MavenAttainGoalListener();
  -        listener.setBaseContext( context );
  -        listener.setPluginManager( this );
  -        WerkzProject werkzProject = new WerkzProject();
  -        werkzProject.addAttainGoalListener( listener );
  -        context.setWerkzProject( werkzProject );
  -        return werkzProject;
  -    }
  -
  -    /**
  -     * Get the Werkz Session
  -     * FIXME: Describe what it's for?
  -     * @param baseContext the maven context the session should use
  -     * @return A Werkz Session
  -     * @throws Exception FIXME For anything
  +     *  Load a user jelly script. This may be a maven.xml file for a project or
  +     *  a shared jelly script used by the reactor.
  +     *
  +     *  @param jellyScript The jelly.
  +     *
  +     *  @throws Exception If an error occurs while attempting to load the file.
        */
  -    private Session getJellySession(MavenJellyContext baseContext) throws Exception
  -    {
  -        // Create the Jelly session
  -        Session session = new JellySession( getJellyOutputSink() );
  -        session.setAttribute( XML_OUTPUT, getJellyOutputSink() );
  -        session.setAttribute( PLUGIN_MANAGER, this );
  -        session.setAttribute( BASE_CONTEXT, baseContext );
  -        return session;
  -    }
  -
  -    private void runJellyScriptHousing( JellyScriptHousing jellyScriptHousing, 
MavenJellyContext context )
  +    public void loadJellyScript( File jellyScript, Project project )
           throws Exception
       {
  -        //!!! I'm not sure how a plugin housing is coming out as null but some
  -        // are. I need to add more tests and clean up the pre-parser.
  +        if ( jellyScript.exists() == false )
  +        {
  +            return;
  +        }
   
  -        if ( jellyScriptHousing != null )
  +        Set originalGoals = new HashSet( 
project.getContext().getWerkzProject().getGoals() );
  +
  +        for ( Iterator i = originalGoals.iterator(); i.hasNext(); )
           {
  -            Script s = jellyScriptHousing.getScript();
  +            Goal eachGoal = (Goal) i.next();
   
  -            if ( s != null )
  +            if ( eachGoal.getAction() == null )
               {
  -                try
  -                {
  -                    // DG HACK 1
  -                    ClassLoader loader = 
Thread.currentThread().getContextClassLoader();
  -                    Thread.currentThread().setContextClassLoader( 
jellyScriptHousing.getClassLoader() );
  -                    // END DG HACK 1
  -                    jellyScriptHousing.getScript().run( context, 
getJellyOutputSink() );
  -                    // DG HACK 2
  -                    Thread.currentThread().setContextClassLoader( loader );
  -                    // END DG HACK 2
  -                }
  -                catch ( Exception e )
  -                {
  -                    System.err.println( "Error running '" + 
jellyScriptHousing.getSource() + "'" );
  -                    throw e;
  -                }
  +                i.remove();
               }
           }
  -    }
   
  -    public MavenJellyContext createPluginContext( String goalName, 
MavenJellyContext parent )
  -    {
  -        JellyScriptHousing jellyScriptHousing = mapper.getPluginHousing( goalName );
  +        transientCacheManager.setPluginScript( jellyScript );
  +        transientCacheManager.parse();
   
  -        return createPluginContext( jellyScriptHousing, parent );
  +        for ( Iterator i = transientCacheManager.getDynaTagLibDecls().iterator(); 
i.hasNext();)
  +        {
  +            prepDynamicTagLib( (String) i.next(), project );
  +        }
  +
  +        // Now we have put the werkz project that belong to the plugin manager into 
the
  +        // the context so any goals with the same name encountered in the maven.xml 
file
  +        // should override goals in the plugin manager werkz project.
  +        JellyUtils.runScript( jellyScript,
  +                              project.getFile().getParentFile().toURL(),
  +                              project.getContext(),
  +                              project.getContext().getXMLOutput() );
       }
   
  -    public MavenJellyContext createPluginContext( JellyScriptHousing 
jellyScriptHousing, MavenJellyContext parent )
  +    /**
  +     *  Perform any required initialization to enable a goal
  +     *  to be met.
  +     *
  +     *  @param initialGoalToPrep The initial goal to prepare for. There may
  +     *         also be additional goals to prep for once prequisite goals
  +     *         are taken into consideration.
  +     *
  +     *  @throws Exception If an error occurs while attempting to
  +     *          prepare for the goal.
  +     */
  +    public void prepForGoal( String initialGoalToPrep, Project project )
  +        throws Exception
       {
  -        // Now we have to modify the context here or create a new one
  -        // so that we can take the following into consideration:
  -        //
  -        // ${plugin}
  -        // ${plugin.dir}
  -        // ${plugin.resources}
  -
  -        Project project = jellyScriptHousing.getProject();
  -        File projectFile = project.getFile();
  -        File unpackedPluginDir = projectFile.getParentFile();
  -
  -        MavenJellyContext pluginContext = new MavenJellyContext( parent );
  -        pluginContext.setVariable( "plugin", jellyScriptHousing.getProject() );
  -        pluginContext.setVariable( "plugin.dir", unpackedPluginDir );
  -        pluginContext.setVariable( "plugin.resources", new File( unpackedPluginDir, 
"plugin-resources" ) );
  +        LinkedList goalsToPrep = new LinkedList();
  +        Set seen = new HashSet();
  +        String goalToPrep = null;
   
  -        // Now I need to merge the properties of the project with the plugin 
properties so
  -        // that plugin properties can be overriden by the project.
  +        goalsToPrep.add( initialGoalToPrep );
   
  -        // The JellyScriptHousing contains the project for this plugin and 
therefore contains the
  -        // properties. We want to make these available in the plugin as simple 
${foo} references.
  -        //pluginContext.getVariables().putAll( 
jellyScriptHousing.getProject().getProjectProperties() );
  +        while ( goalsToPrep.isEmpty() == false )
  +        {
  +            goalToPrep = (String) goalsToPrep.removeFirst();
   
  -        //System.out.println( "jellyScriptHousing = " + 
jellyScriptHousing.getProject().getName() );
  -        //System.out.println( "jellyScriptHousing = " + 
jellyScriptHousing.getProject().getProjectProperty( "maven.compile.target") );
  +            if ( seen.contains( goalToPrep ) )
  +            {
  +                continue;
  +            }
   
  -        return pluginContext;
  -    }
  +            seen.add( goalToPrep );
   
  -    private MavenJellyContext createBaseContext( Project project )
  -    {
  -        // We are making the compileScriptContext the parent so that the werkz
  -        // project is present
  -        MavenJellyContext baseContext = new MavenJellyContext( compileScriptContext 
);
  -        baseContext.setInherit( true );
  +            // We check to see if the goalToPrep has been defined in any user
  +            // jelly script. This allows any goal specified in a plugin to be
  +            // overriden if a user desires.
  +            String spec = transientCacheManager.getPluginCache().getProperty( 
goalToPrep );
   
  -        // Set the created context, and put the project itself in the context. This
  -        // is how we get the ${pom} reference in the project.xml file to work.
  -        baseContext.setProject( project );
  +            if ( spec == null )
  +            {
  +                spec = cacheManager.getPluginCache().getProperty( goalToPrep );
   
  -        // Now we have to setup the classloaders correctly
  +                if ( spec != null )
  +                {
  +                    prepForCallbacks( goalToPrep, project );
  +                    loadPlugin( spec, project );
  +                }
  +            }
   
  -        return baseContext;
  +            // Find any prerequisite goals and add them to the list of
  +            // goals to prepare.
  +            List prereqs = getPrereqs( goalToPrep );
  +            goalsToPrep.addAll( prereqs );
  +        }
       }
   
  -    /** XML output goes to System.out*/
  -    private XMLOutput output;
  +    // ----------------------------------------------------------------------
  +    // P R E P A R A T I O N  M E T H O D S
  +    // ----------------------------------------------------------------------
   
  -    private XMLOutput getJellyOutputSink()
  +    /**
  +     *  Prepare and load plugins based upon callback dependencies.
  +     *
  +     *  @param goalName The goal name.
  +     *
  +     *  @throws Exception If an error occurs while attempting to preprare
  +     *          callback dependencies.
  +     */
  +    void prepForCallbacks( String goalName, Project project )
           throws Exception
       {
  -        if ( output == null )
  +        if ( cacheManager.getCallbackCache().containsKey( goalName + ".pre" ) )
           {
  -            PrintStream consoleOut = System.out;
  -            //PrintStream consoleErr = System.err;
  -
  -            Writer writer = new OutputStreamWriter( consoleOut );
  -            output = XMLOutput.createXMLOutput( writer, false );
  +            loadPlugins( cacheManager.getCallbackCache().getProperty( goalName + 
".pre" ), project );
           }
   
  -        return output;
  +        if ( cacheManager.getCallbackCache().containsKey( goalName + ".post" ) )
  +        {
  +            loadPlugins( cacheManager.getCallbackCache().getProperty( goalName + 
".post" ), project );
  +        }
       }
   
       /**
  -     * FIXME: Not sure why building an Ant project is the plugin manager's 
responisbility
  -     * 
  -     * @param project a maven project
  -     * @param context a maven context
  -     * @return an Ant project
  -     * @throws Exception When any error occurs. FIXME this is bad.
  +     *  Prepare the tag libary for use.
  +     *
  +     *  @param pluginName URI of the tag library to prepare.
  +     *  @param project Project to load the dyna tag libs into.
  +     *
  +     *  @throws Exception if an error occurs while preparing dyna tag libs.
        */
  -    private GrantProject buildAntProject( Project project, MavenJellyContext 
context )
  +    void prepDynaTagLibs( String pluginName, Project project )
           throws Exception
       {
  -        // Create the build listener.
  -        JellyBuildListener buildListener = new JellyBuildListener( 
getJellyOutputSink() );
   
  -        if ( System.getProperty( MavenConstants.DEBUG_ON ).equals( "true" ) )
  -        {
  -            buildListener.setDebug( true );
  -        }
  +        String depPlugins = cacheManager.getPluginDynaTagDepsCache().getProperty( 
pluginName );
   
  -        if ( System.getProperty( MavenConstants.EMACS_MODE_ON ).equals( "true" ) )
  +        if ( depPlugins == null )
           {
  -            buildListener.setEmacsMode( true );
  +            return;
           }
   
  -        // Create our ant project.
  -        GrantProject antProject = new GrantProject();
  -        antProject.setPropsHandler( new JellyPropsHandler( context ) );
  -        antProject.init();
  -        antProject.setBaseDir( project.getFile().getParentFile() );
  -        antProject.addBuildListener( buildListener );
  -
  -        context.setAntProject( antProject );
  -        AntTagLibrary.setProject( context, antProject );
  +        String[] list = StringUtils.split( depPlugins, "," );
   
  -        Path p = new Path( antProject );
  -        p.setPath( project.getDependencyClasspath() );
  -        antProject.addReference( MavenConstants.DEPENDENCY_CLASSPATH, p );
  -
  -        return antProject;
  +        for ( int i = 0; i < list.length; i++ )
  +        {
  +            prepDynamicTagLib( list[i], project );
  +        }
       }
   
  -
  -    private JellyScriptHousing createJellyScriptHousing( Project project, File 
classesDirectory, File jelly )
  +    /**
  +     *  Prepare an individual dyna tag lib for use.
  +     *
  +     *  @param uri URI of the dyna tag.
  +     *  @param project Project to load the dyna tag lib into.
  +     *
  +     *  @throws Exception If an error occurs preparing the dynamic tag library.
  +     */
  +    void prepDynamicTagLib( String uri, Project project )
           throws Exception
       {
  -        InputStream is = null;
  +        String depPlugin = cacheManager.getDynaTagLibCache().getProperty( uri );
   
  -        if ( jelly.exists() )
  +        // Some of the may be currently null because some dyna tag libs aren't
  +        // in plugins but in the driver.jelly file. This needs to be unified where
  +        // everything comes from a plugin.
  +        if ( depPlugin == null )
           {
  -            is = new FileInputStream( jelly );
  +            return;
           }
   
  -        JellyScriptHousing jellyScriptHousing = createJellyScriptHousing( project, 
classesDirectory, is );
  -        jellyScriptHousing.setSource( jelly.getPath() );
  -
  -        return jellyScriptHousing;
  +        loadPlugin( depPlugin, project );
       }
   
       /**
  -     * @param plugin the plugin to create a housing for
  -     * @return a housing
  -     * @throws MalformedURLException 
  -     * @throws Exception
  +     *  Retrieve the prerequisites for a goal.
  +     *
  +     *  @param name The goal name.
  +     *
  +     *  @return A list of <code>String</code> prerequisite goal names.
        */
  -    private JellyScriptHousing createJellyScriptHousing(JellyPlugin plugin)
  -    throws MalformedURLException, Exception
  +    List getPrereqs( String name )
       {
  -        JellyScriptHousing jellyScriptHousing = new JellyScriptHousing();
  -        jellyScriptHousing.setId( plugin.getId() );
  +        String spec = transientCacheManager.getGoalCache().getProperty( name );
  +
  +        if ( spec == null )
  +        {
  +            spec = cacheManager.getGoalCache().getProperty( name );
  +        }
  +
  +        if ( spec == null )
  +        {
  +            return Collections.EMPTY_LIST;
  +        }
  +
  +        int splitLoc = spec.indexOf( ">" );
   
  -        // Now before we even _compile_ the jelly script you must set the 
classloader because
  -        // the whole process needs to be able to resolve the tags. I thought a 
StaticTag was
  -        // supposed to be created and the search deferred but this is _not_ the 
case.
  -        jellyScriptHousing.setClassLoader( plugin.getClassLoader() );
  -        jellyScriptHousing.setProject( plugin.getProject() );
  -        jellyScriptHousing.setScript( 
plugin.getCompiledScriptFor(compileScriptContext) );
  +        if ( ( splitLoc < 0 )
  +            ||
  +            ( splitLoc + 1 ) == spec.length() )
  +        {
  +            return Collections.EMPTY_LIST;
  +        }
  +
  +        String prereqSpec = spec.substring( splitLoc + 1 );
   
  -        return jellyScriptHousing;
  +        StringTokenizer tokens = new StringTokenizer( prereqSpec, "," );
  +
  +        List prereqs = new ArrayList();
  +
  +        while ( tokens.hasMoreTokens() )
  +        {
  +            prereqs.add( tokens.nextToken() );
  +        }
  +
  +        return prereqs;
       }
   
  -    private JellyScriptHousing createJellyScriptHousing( Project project, File 
unpackedPluginDirectory, InputStream jelly )
  +    // ----------------------------------------------------------------------
  +    // P L U G I N  L O A D I N G
  +    // ----------------------------------------------------------------------
  +
  +    /**
  +     *  Load the specified plugin.
  +     *
  +     *  @param name The name of the plugin to load.
  +     *
  +     *  @throws Exception If an error occurs while initializing the plugin.
  +     */
  +    public void loadPlugin( String name, Project project )
           throws Exception
       {
  -        JellyScriptHousing jellyScriptHousing = new JellyScriptHousing();
  +        if ( isLoaded( project, name ) )
  +        {
  +            return;
  +        }
   
  -        // Now we are going to create a ClassLoader for the plugins classes and the 
JARs
  -        // that it depends on for executing.
  -        ForeheadClassLoader classLoader = new ForeheadClassLoader( 
mavenRootClassLoader, project.getId() );
  +        File pluginScript = getPluginScript( name );
   
  -        if ( unpackedPluginDirectory != null )
  +        if ( pluginScript.exists() == false )
           {
  -            // We will add the plugin classes to the plugin class loader.
  -            classLoader.addURL( unpackedPluginDirectory.toURL() );
  +            return;
           }
   
  -        // We will add the JARs that have been instructed to be place in the class 
loader
  -        // for use in the plugin in the plugin class loader.
  -        processDependencies( project, classLoader );
  +        // We need to make sure all the dyna tag libs are initialized for this
  +        // plugin.
  +        prepDynaTagLibs( name, project );
   
  -        //displayClassLoaderContents( project, classLoader );
  +        File unpackedPluginDir = getUnpackedPluginDir( name );
   
  -        // Now before we even _compile_ the jelly script you must set the 
classloader because
  -        // the whole process needs to be able to resolve the tags. I thought a 
StaticTag was
  -        // supposed to be created and the search deferred but this is _not_ the 
case.
  -        compileScriptContext.setClassLoader( classLoader );
  +        // Use classworlds
  +        Forehead.getInstance().getClassLoader( "root.maven" )
  +            .addURL( unpackedPluginDir.toURL() );
   
  -        // Now lets compile the script once so we can use it repeatedly.
  -        Script script = null;
  +        Project pluginProject =
  +            MavenUtils.getProject( new File( unpackedPluginDir,
  +                                    "project.xml" ),
  +                                    project.getContext(),
  +                                    false );
   
  -        // Projects may not have a maven.xml file.
  -        if ( jelly != null )
  +        if ( isPluginProcessed( name ) == false )
           {
  -            try
  -            {
  -                script = JellyUtils.compileScript( jelly, compileScriptContext );
  -            }
  -            catch ( Exception e )
  -            {
  -                e.printStackTrace();
  -            }
  +            pluginProject.verifyDependencies();
  +
  +            // Mark the plugin as processed.
  +            FileUtils.fileWrite( getPluginProcessedMarker( name ).getPath(),
  +                                 "plugin has been processed.");
           }
   
  -        jellyScriptHousing.setClassLoader( classLoader );
  -        jellyScriptHousing.setProject( project );
  -        jellyScriptHousing.setScript( script );
  -        jellyScriptHousing.setId( project.getId() );
  +        // place dependencies on the right classloaders
  +        pluginProject.processDependencies();
  +        
  +        // We need to create a separate context for the plugin.jelly script to
  +        // run against because we need our values of "plugin" and "plugin.dir"
  +        // to have distinct values. Everything else can be taken from the
  +        // project's context. We also want project properties to override any
  +        // default plugin properties. When we make the pluginContext, context
  +        // inheritance is on so when we integrate the plugin properties if the
  +        // project has already defined an overriding value it won't get
  +        // clobbered. The plugin defaults will only be used if the
  +        // project hasn't provided a value.
  +        MavenJellyContext pluginContext =
  +            new MavenJellyContext( project.getContext() );
  +        MavenUtils.integrateMapInContext(
  +                        getPluginProperties( unpackedPluginDir ),
  +                        pluginContext );
  +        pluginContext.setVariable( "plugin", pluginProject );
  +        pluginContext.setVariable( "plugin.dir", unpackedPluginDir );
   
  -        return jellyScriptHousing;
  -    }
  +        // Set a context variable that points to the plugin resources directory
  +        pluginContext.setVariable( "plugin.resources",
  +            new File( unpackedPluginDir, "plugin-resources" ) );
   
  -    private void displayClassLoaderContents( Project project, ForeheadClassLoader 
classLoader )
  -    {
  -        URL[] urls = classLoader.getURLs();
  +        project.addPluginContext( pluginProject.getId(), pluginContext );
   
  -        System.out.println( "project.getName() = " + project.getName() );
  +        JellyUtils.runScript( pluginScript,
  +                              unpackedPluginDir.toURL(),
  +                              pluginContext,
  +                              pluginContext.getXMLOutput() );
   
  -        for ( int i = 0; i < urls.length; i++ )
  +        // The project werkz project seems to come up null when there is no 
maven.xml
  +        // that is processed first. An inheritance bug in the context it seems.
  +        if ( project.getContext().getWerkzProject() == null )
           {
  -            System.out.println( "urls[" + i + "] = " + urls[i] );
  +            project.getContext().setWerkzProject( pluginContext.getWerkzProject() );
           }
  -        
  -        ClassLoader parent = classLoader.getParent();
  -        if (parent != null && parent instanceof ForeheadClassLoader)
  +
  +        // The plugin has now been loaded for use for a particular project
  +        // So add it to the list.
  +        loadedPlugins.add( project.hashCode() + name );
  +    }
  +
  +    /**
  +     *  Load plugins specified in a whitespace delimited string.
  +     *
  +     *  @param names The whitespace delimited string of plugin names.
  +     *
  +     *  @throws Exception If an error occurs while attempting to load
  +     *          the plugins.
  +     */
  +    void loadPlugins( String names, Project project )
  +        throws Exception
  +    {
  +        StringTokenizer tokens = new StringTokenizer( names, "," );
  +
  +        while ( tokens.hasMoreTokens() )
           {
  -            System.out.println("Displaying Parent classloader: ");
  -            displayClassLoaderContents(project, 
(ForeheadClassLoader)classLoader.getParent());
  +            loadPlugin( tokens.nextToken(), project );
           }
       }
   
  +    // ----------------------------------------------------------------------
  +    // C A C H I N G
  +    // ----------------------------------------------------------------------
  +
       /**
  -     * process the dependencies for this project
  +     *  Cache a plugin.
  +     *
  +     *  @param name The plugin name.
  +     *
  +     *  @throws Exception If an error occurs while attempting to analyze
  +     *          and cache plugin information.
        */
  -    public static void processDependencies( Project project, ForeheadClassLoader 
classLoader )
  -        throws MalformedURLException
  +    void cachePlugin( String name )
  +        throws Exception
       {
  -        if ( project.getArtifacts() == null )
  +        log.debug( "Processing Plugin: " + name );
  +
  +        File pluginScript = getPluginScript( name );
  +
  +        // There are some plugins that don't have plugin.jelly scripts like
  +        // the examples plugin. This certainly isn't the norm but we want
  +        // avoid useless error messages filling up the console.
  +        if ( pluginScript.exists() )
           {
  -            return;
  +            cacheManager.setPluginScript( pluginScript );
  +            cacheManager.parse();
           }
  +    }
   
  -        for ( Iterator i = project.getArtifacts().iterator(); i.hasNext(); )
  +    /**
  +     *  Save cache information to disk.
  +     *
  +     *  @throws Exception If an error occurs while saving the cache.
  +     */
  +    void saveCache()
  +        throws Exception
  +    {
  +        cacheManager.saveCache();
  +    }
  +
  +    /**
  +     * Invalidate cache information for a single plugin.
  +     *
  +     * @param pluginName The name of the plugin to invalid cache entries.
  +     */
  +    void invalidateCache( String pluginName )
  +    {
  +        for ( Iterator i = cacheManager.getGoalCache().keySet().iterator(); 
i.hasNext(); )
           {
  -            Artifact artifact = (Artifact) i.next();
  -            Dependency dependency = artifact.getDependency();
  -            String classloaderProperty = dependency.getProperty( "classloader" );
  -
  -            // Only add compile type dependencies to classloader
  -            // what about ejbs etc
  -            if ( dependency.getType().equals( "jar" ) )
  +            String eachGoal = (String) i.next();
  +
  +            if ( cacheManager.getPluginCache().getProperty( eachGoal ).equals( 
pluginName ) )
               {
  -                // We have the jar and the classloader to push it into so
  -                // lets do it!
  -                if ( artifact.exists() )
  -                {
  -                    if ( classloaderProperty != null )
  -                    {
  -                        ForeheadClassLoader otherClassLoader = 
  -                            
Forehead.getInstance().getClassLoader(classloaderProperty);
  -                        if (otherClassLoader != null)
  -                        {
  -                            otherClassLoader.addURL( artifact.getFile().toURL() );
  -                        }
  -                    }
  -                    else
  -                    {
  -                        classLoader.addURL( artifact.getFile().toURL() );
  -                    }
  -                }
  +                i.remove();
  +                cacheManager.getPluginCache().remove( eachGoal );
  +                cacheManager.getCallbackCache().remove( eachGoal + ".pre" );
  +                cacheManager.getCallbackCache().remove( eachGoal + ".post" );
               }
           }
  +    }
   
  +    /**
  +     *  Determine if a plugin has been cached.
  +     *
  +     *  @param pluginName The name of the plugin to test.
  +     *
  +     *  @return <code>true</code> if the plugin has already been cached,
  +     *          otherwise <code>false</code>.
  +     */
  +    boolean isCached( String pluginName )
  +    {
  +        return cacheManager.getPluginCache().contains( pluginName );
       }
   
       /**
  -     *  Load plugins specified in a whitespace delimited string.
  +     *  Determine if a goal has been cached.
        *
  -     *  @param names The whitespace delimited string of plugin names.
  +     *  @param name The name of the goal to test.
        *
  -     *  @throws Exception If an error occurs while attempting to load
  -     *          the plugins.
  +     *  @return <code>true</code> if the goal has already been cached,
  +     *          otherwise <code>false</code>.
        */
  -    void loadPlugins( String names, Project project )
  -        throws Exception
  +    boolean isGoalCached( String name )
       {
  -        StringTokenizer tokens = new StringTokenizer( names, "," );
  +        return cacheManager.getGoalCache().containsKey( name );
  +    }
   
  -        while ( tokens.hasMoreTokens() )
  -        {
  -            loadPlugin( tokens.nextToken() );
  -        }
  +    Set getTagLibsCache()
  +    {
  +        return cacheManager.getDynaTagLibCache().keySet();
       }
   
       /**
  @@ -828,7 +891,7 @@
       File getPluginProcessedMarker( String pluginName )
       {
           return new File( new File( getUnpackedPluginsDir(), pluginName ),
  -                         ".processed" );
  +                            ".processed" );
       }
   
       /**
  @@ -851,11 +914,44 @@
        *  @return <code>true</code> if the plugin has been loaded,
        *          otherwise <code>false</code>.
        */
  -    boolean isLoaded( String id )
  +    boolean isLoaded( Project project, String name )
  +    {
  +        return loadedPlugins.contains( project.hashCode() + name );
  +    }
  +
  +    /**
  +     *  Retrieve the plugin's default properties.
  +     *
  +     *  @param unpackedPluginDir The location of the unpacked plugin.
  +     *
  +     *  @return The default properties file for the plugin, or <code>null</code>
  +     *          if no such plugin.
  +     *
  +     *  @throws IOException If an IO error occurs while attempting to read the
  +     *       plugin's properties.
  +     */
  +    Properties getPluginProperties( File unpackedPluginDir )
  +        throws IOException
       {
  -        return loadedPlugins.get( id ) != null;
  +        File propsFile = new File( unpackedPluginDir, PLUGIN_PROPERTIES_NAME );
  +
  +        if ( propsFile.exists() == false )
  +        {
  +            return null;
  +        }
  +
  +        Properties props = new Properties();
  +
  +        FileInputStream in = new FileInputStream( propsFile );
  +
  +        props.load( in );
  +
  +        in.close();
  +
  +        return props;
       }
   
  +
       /**
        *  Retrieve the directory where the specified plugin is unpacked.
        *
  @@ -869,6 +965,20 @@
       }
   
       /**
  +     *  Retrieve the plugin's entry-point jelly script.
  +     *
  +     *  @param pluginName The name of the plugin.
  +     *
  +     *  @return The entry-point script for the plugin, or <code>null</code> if
  +     *          no such plugin.
  +     */
  +    File getPluginScript( String pluginName )
  +    {
  +        return new File( getUnpackedPluginDir( pluginName ),
  +            PLUGIN_SCRIPT_NAME );
  +    }
  +
  +    /**
        *  Sets the pluginsDir attribute of the PluginManager object
        *
        *  @param pluginsDir The maven plugin directory.
  @@ -896,6 +1006,7 @@
       void setUnpackedPluginsDir( File unpackedPluginsDir )
       {
           this.unpackedPluginsDir = unpackedPluginsDir;
  +        cacheManager.setUnpackedPluginsDir( unpackedPluginsDir );
       }
   
       /**
  @@ -906,5 +1017,31 @@
       File getUnpackedPluginsDir()
       {
           return unpackedPluginsDir;
  +    }
  +
  +    /**
  +     * Load and install a plugin
  +     * @todo should check if it's already installed.
  +     * @todo I'm not sure if caching needs to be called.
  +     * @param file
  +     */
  +    public void installPlugin(Project project, File file) throws Exception
  +    {
  +        // copy the file to the unpacked plugins dir
  +        FileUtils.copyFileToDirectory(file, getPluginsDir());
  +        String pluginName = file.getCanonicalFile().getName();
  +        pluginName = pluginName.substring(0, pluginName.indexOf(".jar"));
  +        String newFileName = getPluginsDir().getCanonicalPath() 
  +            + File.separator + file.getCanonicalFile().getName();
  +        // expand it
  +        Expand unzipper = new Expand();
  +        unzipper.setSrc( new File(newFileName));
  +        File unzipDir = new File( getUnpackedPluginsDir(), pluginName);
  +        unzipper.setDest( unzipDir );
  +        unzipper.execute();
  +        // load it
  +        loadPlugin(pluginName, project);
  +        cachePlugin(pluginName);
  +        // FIXME: Does it need caching too?
       }
   }
  
  
  
  1.14      +2 -2      maven/src/java/org/apache/maven/plugin/PluginCacheManager.java
  
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to