mcconnell    2003/11/17 00:18:46

  Added:       repository/main .cvsignore maven.xml project.xml
               repository/main/src/java/org/apache/avalon/repository
                        ApplicationDirective.java Bootstrapper.java
                        InitialRepositoryFactory.java package.html
  Log:
  Definition of the single repository bootstrap system.
  
  Revision  Changes    Path
  1.1                  avalon-sandbox/repository/main/.cvsignore
  
  Index: .cvsignore
  ===================================================================
  maven.log
  velocity.log
  build.properties
  target
  .classpath
  .project
  
  
  1.1                  avalon-sandbox/repository/main/maven.xml
  
  Index: maven.xml
  ===================================================================
  <project default="merlin:build" xmlns:maven="jelly:maven" xmlns:j="jelly:core" 
xmlns:util="jelly:util" xmlns:ant="jelly:ant">
  
    <!--
    ###########################################################################
    # Create the .impl metadata.                                               #
    # This contains the information used by the factory to identify the       #
    # the implementation artifact classpath, factory, and whever else         #
    # we need to include this jar as the implementation strategy.             #
    ###########################################################################
    -->
  
    <postGoal name="java:compile">
  
      <j:set var="impl" 
value="${pom.getDependency('avalon-repository:avalon-repository-impl')}"/>
  
      <ant:mkdir dir="${maven.build.dir}/classes/${pom.groupId}"/>
      <ant:echo 
file="${maven.build.dir}/classes/${pom.groupId}/${pom.artifactId}.meta">
  #
  # Repository Implementation target description.
  # 
  
  avalon.target.group = ${impl.groupId}
  avalon.target.name = ${impl.artifactId}
  avalon.target.version = ${impl.version}
  avalon.target.repos = ${maven.repo.remote}
  
  #
  # Factory class and parameters.
  #
  
  avalon.target.factory.class = 
org.apache.avalon.repository.impl.DefaultRepositoryFactory
  avalon.target.factory.method = create
  #avalon.target.factory.key.0 = some-key
  #avalon.target.factory.key.0 = another-key
  
  #
  # EOF
  #
  </ant:echo>
      <ant:mkdir dir="${maven.repo.local}/${pom.groupId}"/>
      <ant:copy toDir="${maven.repo.local}/${pom.groupId}" 
         file="${maven.build.dir}/classes/${pom.groupId}/${pom.artifactId}.meta"/>
    </postGoal>
  
    <preGoal name="jar:jar">
      <j:forEach var="dep" items="${pom.dependencies}">
        <j:if test="${dep.getId() != 'avalon-repository:avalon-repository-impl'}">
          <unzip src="${pom.getDependencyPath( dep.getId() )}" 
            dest="${maven.build.dir}/classes"
            excludes="/META-INF/**"/>
        </j:if>
      </j:forEach>
    </preGoal>
  
  </project>
  
  
  
  1.1                  avalon-sandbox/repository/main/project.xml
  
  Index: project.xml
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <project>
  
    <extend>${basedir}/../project.xml</extend>
  
    <groupId>avalon-repository</groupId>
    <id>avalon-repository-main</id>
    <name>Avalon Repository Bootstap</name>
    <currentVersion>1.2-dev</currentVersion>
  
    <package>org.apache.avalon.repository</package>
  
    <inceptionYear>2002</inceptionYear>
    <shortDescription>Avalon Repository Bootstap</shortDescription>
    
    <dependencies>
      <dependency>
        <groupId>avalon-repository</groupId>
        <artifactId>avalon-repository-api</artifactId>
        <version>1.2-dev</version>
      </dependency>
      <dependency>
        <groupId>avalon-repository</groupId>
        <artifactId>avalon-repository-spi</artifactId>
        <version>1.2-dev</version>
      </dependency>
      <dependency>
        <groupId>avalon-repository</groupId>
        <artifactId>avalon-repository-impl</artifactId>
        <version>1.2-dev</version>
      </dependency>
    </dependencies>
  
  </project>
  
  
  
  1.1                  
avalon-sandbox/repository/main/src/java/org/apache/avalon/repository/ApplicationDirective.java
  
  Index: ApplicationDirective.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.avalon.repository ;
  
  
  import java.util.Properties ;
  
  
  /**
   * A build descriptor can be generated from a jar that has extra jar build 
   * properties packaged with it.
   * 
   * @author <a href="mailto:[EMAIL PROTECTED]">Alex Karasulu</a>
   * @author $Author: mcconnell $
   * @version $Revision: 1.1 $
   */
  public class ApplicationDirective
  {
      //-----------------------------------------------------------
      // static
      //-----------------------------------------------------------
  
     /** 
      * the key used to get the defualt comma delimited 
      * repository urls
      */
      public static final String REPOS_KEY = "avalon.target.repos" ;
  
     /** 
      * the key used to get the aplication artifact group
      */
      public static final String GROUP_KEY = "avalon.target.group" ;
  
     /** 
      * the key used to get the artifact name within the group
      */
      public static final String NAME_KEY = "avalon.target.name" ;
  
     /** 
      * the version of the application artifact
      */
      public static final String VERSION_KEY = "avalon.target.version" ;
  
      //-----------------------------------------------------------
      // static
      //-----------------------------------------------------------
      
     /** 
      * the jar descriptor that identifes the implemetation jar
      */
      private final JarDescriptor m_implementation ;
  
     /** 
      * default repos that will contain this jar and project descriptors 
      */
      private final String[] m_repos ;
  
      /**
       * Creates a ApplicationDirective
       * 
       * @param reference the service provider implementation reference
       * @param a_props supplimentary properties
       */
      public ApplicationDirective( ArtifactReference reference, String[] repositories 
) 
        throws RepositoryException
      {
          if( reference == null ) throw new NullPointerException( "reference" );
          if( repositories == null ) throw new NullPointerException( "repositories" );
  
          Properties properties = RepositoryUtils.getProperties( repositories, 
reference );
  
          final String group = properties.getProperty( GROUP_KEY );
          final String name = properties.getProperty( NAME_KEY  );
          final String version = properties.getProperty( VERSION_KEY );
  
          m_implementation = new JarDescriptor( group, name, version );
          
          // gets the comma separated repository list
          String[] repos = 
            RepositoryUtils.getDelimited( ',', properties.getProperty( REPOS_KEY ) ) ;
          if( repos != null )
          {
              m_repos = repos;
          }
          else
          {
              m_repos = repositories;
          }
      }
  
      /**
       * Gets the artifact descriptor for the jar.
       * 
       * @return the artifact descriptor for the jar
       */
      public JarDescriptor getJarDescriptor()
      {
          return m_implementation;
      }
      
      /**
       * Gets the default or bootstrap repositories guaranteed to contain the jar.
       * 
       * @return the repo urls as strings
       */
      public String[] getDefaultRepositories()
      {
          return m_repos ;
      }
  }
  
  
  
  1.1                  
avalon-sandbox/repository/main/src/java/org/apache/avalon/repository/Bootstrapper.java
  
  Index: Bootstrapper.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.avalon.repository ;
  
  
  import java.text.ParseException ;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method ;
  import java.lang.reflect.InvocationTargetException ;
  
  
  /**
   * Application and component bootstrapper used to instantiate, and or invoke
   * Classes and their methods within newly constructed Repository ClassLoaders.
   * 
   * @author <a href="mailto:[EMAIL PROTECTED]">Alex Karasulu</a>
   * @author $Author: mcconnell $
   * @version $Revision: 1.1 $
   */
  public class Bootstrapper
  {
      /** The repository used by this bootstrapper */
      private final Repository m_repository ;
      /** The Jar artifact descriptor containing the target classes */
      private final JarDescriptor m_descriptor ;
      /** The ClassLoader used to load and instantiate target classes */
      private final ClassLoader m_loader ;
      
      
      /**
       * Creates a Bootstrapper for a specific target Jar artifact's classes.
       */
      public Bootstrapper( Repository a_repository, JarDescriptor a_descriptor )
          throws RepositoryException
      {
          m_repository = a_repository ;
          m_descriptor = a_descriptor ;
          m_loader = a_repository.getClassLoader( a_descriptor ) ;
      }
  
      
      /**
       * Gets the ClassLoader used by this Bootstrapper.
       * 
       * @return the ClassLoader built by the Repository
       */
      public ClassLoader getClassLoader()
      {
          return m_loader ;
      }
      
  
      /**
       * Invokes the main application entry point for a class.
       * 
       * @param a_fqcn the fully qualified class name
       * @param a_args the arguments to pass-thro to the main of the application
       * @throws RepositoryException on any class loading or invocation failures
       */
      public void main( String a_fqcn, String[] a_args )
          throws RepositoryException
      {
          Class l_clazz = null ;
          Method l_main = null ;
          
          try 
          {
              l_clazz = m_loader.loadClass( a_fqcn ) ;
              l_main = l_clazz.getMethod( a_fqcn, new Class[] {String[].class} ) ;
              
              if ( l_main.getReturnType() != Void.TYPE )
              {
                  throw new RepositoryException( "Invalid main() in " + a_fqcn 
                          + " has a non-void return type of " 
                          + l_main.getReturnType() ) ;
              }
              
              l_main.invoke( null, a_args ) ;
          }
          catch ( InvocationTargetException e )
          {
              throw new RepositoryException( "Failed to invoke target main()"
                      + " in class " + a_fqcn ) ;
          }
          catch ( IllegalAccessException e )
          {
              throw new RepositoryException( "Cannot invoke non-public main()"
                      + " in class " + a_fqcn ) ;
          }
          catch ( NoSuchMethodException e )
          {
              throw new RepositoryException( a_fqcn + " Does not contain a main "
                      + "method with a sole String [] argument.", e ) ; 
          }
          catch ( ClassNotFoundException e )
          {
              throw new RepositoryException( "ClassLoader for repository Jar "
                      + "artifact " + m_descriptor + " could not find " 
                      + a_fqcn, e ) ;
          }
      }
      
      
      /**
       * Instantiates a runnable using a default constructor and calls its run
       * method.
       * 
       * @param a_fqcn the fully qualified class name of the Runnable 
       * @throws RepositoryException on any class loading or invokation failures
       */
      public void run( String a_fqcn ) throws RepositoryException
      {
          Class l_clazz = null ;
          Runnable l_runnable = null ;
          
          try
          {
              l_clazz = m_loader.loadClass( a_fqcn ) ;
              l_runnable = ( Runnable ) l_clazz.newInstance() ;
              l_runnable.run() ;
          }
          catch ( ClassCastException e )
          {
              throw new RepositoryException( a_fqcn + " is not a Runnable", e ) ;
          }
          catch ( InstantiationException e )
          {
              throw new RepositoryException( a_fqcn + " in " + m_descriptor
                      + " does not contain a default constructor" ) ;
          }
          catch ( IllegalAccessException e )
          {
              throw new RepositoryException( "Cannot invoke non-public run()"
                      + " in class " + a_fqcn ) ;
          }
          catch ( ClassNotFoundException e )
          {
              throw new RepositoryException( "Could not find " + a_fqcn 
                      + " in repository jar artifact " + m_descriptor 
                      + " or in any one of its dependent Jars", e ) ;
          }
      }
  
  
      /**
       * Invokes a static method on a class.
       * 
       * @param a_fqcn the fully qualified class name
       * @param a_method the name of the method to invoke
       * @param a_types the fqcn of the parameters
       * @param a_args the arguments to the method
       * @return the methods return value if one exists, or null if method is void
       */
      public Object invoke( String a_fqcn, String a_method, String [] a_types, 
                            Object [] a_args )
          throws RepositoryException
      {
          Class l_clazz = loadClass( a_fqcn ) ;
          Class [] l_types = new Class[a_types.length] ;
          
          /** Get all the argument classes */
          for ( int ii = 0; ii < a_types.length; ii++ )
          {
              l_types[ii] = loadClass( a_types[ii] ) ;
          }
          
          Method l_method = null ;
          try
          {
              l_method = l_clazz.getMethod( a_method, l_types ) ;
              return l_method.invoke( null, a_args ) ;
          }
          catch ( InvocationTargetException e )
          {
              throw new RepositoryException( "Failed to invoke static target "
                      + toSignature( a_method, a_types ) + " in class " 
                      + a_fqcn ) ;
          }
          catch ( IllegalAccessException e )
          {
              throw new RepositoryException( "Cannot access static method " 
                      + toSignature( a_method, a_types ) + " in class "
                      + a_fqcn, e ) ;
          }
          catch ( NoSuchMethodException e )
          {
              throw new RepositoryException( "Could not find static method with"
                      + " matching signature " + toSignature( a_method, a_types ) 
                      + " for class " + a_fqcn, e ) ;
          }
      }
      
      
      /**
       * Creates a new instance of a class using the default constructor.
       * 
       * @param a_fqcn the fully qualified name of the class to create an inst of
       * @return the instance created
       * @throws RepositoryException if the instantiation fails
       */
      public Object newInstance( String a_fqcn ) throws RepositoryException
      {
          Class l_clazz = loadClass( a_fqcn ) ;
          
          try
          {
              return l_clazz.newInstance() ;
          }
          catch ( IllegalAccessException e )
          {
              throw new RepositoryException( "A public accessible default "
                      + "constructor dies not exist for " + a_fqcn, e ) ;
          }
          catch ( InstantiationException e )
          {
              throw new RepositoryException( "Failure while creating an"
                      + " instance of " + a_fqcn 
                      + " via the default constructor", e ) ;
          }
      }
      
      
      /**
       * Creates a new instance of a class using a constructor taking arguments.
       * 
       * @param a_fqcn the fully qualified name of the class to create an inst of
       * @param a_types the fully qualified names of constructor parameter types
       * @param a_args the arguments to the constructor
       * @return the newly created instance 
       * @throws RepositoryException if the instantiation fails
       */
      public Object newInstance( String a_fqcn, String[] a_types, 
                                 Object[] a_args )
          throws RepositoryException
      {
          Class l_clazz = loadClass( a_fqcn ) ;
          Class[] l_types = new Class[a_types.length] ;
          
          for ( int ii = 0; ii < a_types.length; ii++ )
          {
              l_types[ii] = loadClass( a_types[ii] ) ;
          }
          
          try 
          {
              Constructor l_constructor = l_clazz.getConstructor( l_types ) ;
              return l_constructor.newInstance( a_args ) ;
          }
          catch ( InstantiationException e )
          {
              throw new RepositoryException( 
                      "Failed to instantiate with constructor "
                      + toSignature( getConstructor( a_fqcn ), a_types ), e ) ;
          }
          catch ( NoSuchMethodException e )
          {
              throw new RepositoryException( 
                      "Could not find a constructor with signature " 
                      + toSignature( getConstructor( a_fqcn ), a_types ), e ) ;
          }
          catch ( InvocationTargetException e )
          {
              throw new RepositoryException( "Failed to invoke constructor "
                      + toSignature( getConstructor( a_fqcn ), a_types ), e ) ;
          }
          catch ( IllegalAccessException e )
          {
              throw new RepositoryException( "Cannot access constructor " 
                      + toSignature( getConstructor( a_fqcn ), a_types ), e ) ;
          }
      }
      
      
      /**
       * Gets the name of the constructor given the fully qualified class name.
       * 
       * @param a_fqcn the fully qualified class name
       * @return the name of the constructor
       */
      public String getConstructor( String a_fqcn )
      {
          int l_lastDot = a_fqcn.indexOf( '.' ) ;
          
          // Class is in default package so a_fqcn = cn = constructor
          if ( -1 == l_lastDot )
          {
              return a_fqcn ;
          }
          
          return a_fqcn.substring( l_lastDot + 1 ) ;
      }
      
  
      /**
       * Invokes a method on an object.
       * 
       * @param a_obj the object to invoke a method on
       * @param a_method the method to invoke
       * @param a_argTypes the fqcn of the parameters 
       * @param a_args the arguments to method
       * @return a return value if one is returned, otherwise null
       * @throws RepositoryException
       */
      public Object invoke( Object a_obj, String a_method, String [] a_argTypes, 
                            Object[] a_args )
          throws RepositoryException
      {
          Class [] l_argClasses = new Class[a_argTypes.length] ;
          
          /** Get all the argument classes */
          for ( int ii = 0; ii < a_argTypes.length; ii++ )
          {
              l_argClasses[ii] = loadClass( a_argTypes[ii] ) ;
          }
          
          Method l_method = null ;
          try
          {
              l_method = a_obj.getClass().getMethod( a_method, l_argClasses ) ;
              return l_method.invoke( a_obj, a_args ) ;
          }
          catch ( InvocationTargetException e )
          {
              throw new RepositoryException( "Failed to invoke target "
                      + toSignature( a_method, a_argTypes ) + " in class " 
                      + a_obj.getClass(), e ) ;
          }
          catch ( IllegalAccessException e )
          {
              throw new RepositoryException( "Cannot access method " 
                      + toSignature( a_method, a_argTypes ) + " in class "
                      + a_obj.getClass(), e ) ;
          }
          catch ( NoSuchMethodException e )
          {
              throw new RepositoryException( "Could not find method with matching"
                      + " signature " + toSignature( a_method, a_argTypes ) 
                      + " for object of class " + a_obj.getClass(), e ) ;
          }
      }
      
      
      /**
       * Loads a class using the ClassLoader created by the Repository.
       * 
       * @param a_fqcn the fully qualified class name 
       * @return the Class loaded using the Repository built ClassLoader
       * @throws RepositoryException if the class could not be found
       */
      public Class loadClass( String a_fqcn ) throws RepositoryException
      {
          try
          {
              return m_loader.loadClass( a_fqcn ) ;
          }
          catch ( ClassNotFoundException e )
          {
              throw new RepositoryException( "Could not find " + a_fqcn 
                      + " in repository jar artifact " + m_descriptor 
                      + " or in any one of its dependent Jars", e ) ;
          }
      }
      
      
      /**
       * Constructs a String representing the signature of an method.
       * 
       * @param a_method the name of the method
       * @param a_types the fully qualified class names of the method parameters
       * @return the signature String
       */
      public String toSignature( String a_method, String [] a_types )
      {
          StringBuffer l_buf = new StringBuffer( a_method ) ;
          
          l_buf.append( '(' ) ;
          for ( int ii = 0; ii < a_types.length; ii++ )
          {
              l_buf.append( a_types[ii] ) ;
              
              if ( ii < a_types.length )
              {
                  l_buf.append( ',' ) ;
              }
          }
          l_buf.append( ')' ) ;
          
          return l_buf.toString() ;
      }
  
  
      /**
       * Main wrapper.
       * 
       * @todo add more properties to allow full repo specification via 
       * system properties including a repository implementation replacement.
       * 
       * @param a_args
       */
      public static void main( String [] a_args )
      {
          String l_jarSpec = System.getProperty( "repository.application.jar" ) ;
          String l_fqcn = System.getProperty( "repository.application.class" ) ;
          
          if ( null == l_jarSpec )
          {
              System.err.println( "The repository application jar was not "
                      + "specified so we cannot continue ..." ) ;
              System.exit( -1 ) ;
          }
          
          if ( null == l_fqcn )
          {
              System.err.println( "The main application class was not "
                      + "specified so we cannot continue ..." ) ;
              System.exit( -1 ) ;
          }
          
          Repository l_repository ;
          JarDescriptor l_jar = null ;
          Bootstrapper l_bootstrapper ;
          try
          {
              l_jar = new JarDescriptor( l_jarSpec ) ;
          }
          catch ( ParseException e )
          {
              e.printStackTrace() ;
              System.exit( -1 ) ;
          }
          
          try
          {
              InitialRepositoryFactory l_factory = 
                  new InitialRepositoryFactory() ;
              RepositoryContext l_context = l_factory.getDefaultContext() ;
              l_repository = l_factory.create( l_context ) ;
              l_bootstrapper = new Bootstrapper( l_repository, l_jar ) ;
              l_bootstrapper.main( l_fqcn, a_args ) ;
          }
          catch ( RepositoryException e )
          {
              e.printStackTrace() ;
              System.exit( -1 ) ;
          }
      }
  }
  
  
  
  1.1                  
avalon-sandbox/repository/main/src/java/org/apache/avalon/repository/InitialRepositoryFactory.java
  
  Index: InitialRepositoryFactory.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Jakarta", "Apache Avalon", "Avalon Framework" and
      "Apache Software Foundation"  must not be used to endorse or promote
      products derived  from this  software without  prior written
      permission. For written permission, please contact [EMAIL PROTECTED]
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation. For more  information on the
   Apache Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.avalon.repository ;
  
  
  import java.io.File ;
  import java.io.IOException ;
  import java.io.InputStream ;
  import java.io.FileOutputStream ;
  
  import java.util.ArrayList ;
  import java.util.Properties ;
  import java.text.ParseException ;
  
  import java.net.URL ;
  import java.net.URLConnection ;
  import java.net.URLClassLoader ;
  import java.net.HttpURLConnection ;
  import java.net.MalformedURLException ;
  
  import javax.naming.NamingException ;
  import javax.naming.NamingEnumeration ;
  import javax.naming.directory.Attributes ;
  
  
  /**
   * Sets up the environment to create repositories by downloading the required 
   * jars, preparing a ClassLoader and delegating calls to repository factory 
   * methods using the newly configured ClassLoader.
   * 
   * @author <a href="mailto:[EMAIL PROTECTED]">Alex Karasulu</a>
   * @author $Author: mcconnell $
   * @version $Revision: 1.1 $
   */
  public class InitialRepositoryFactory implements RepositoryFactory
  {
      public static final String REPOSITORY_GROUP_NAME = 
          "avalon-repository" ;
      public static final String REPOSITORY_APPLICATION_NAME = 
          "avalon-repository-main" ;
  
      public static final String DEFAULT_FACTORY = 
          "org.apache.avalon.repository.impl.DefaultRepositoryFactory" ;
  
      public static final Properties PROPERTIES = 
          createDefaultProperties();
  
      public static final ArtifactReference REFERENCE = 
          new ArtifactReference( REPOSITORY_GROUP_NAME, REPOSITORY_APPLICATION_NAME );
  
      private static final String[] DEFAULT_REPOSITORIES =
          new String[]{ "http://dpml.net/"; };
  
     /**
      * Build the properties that declare the default repository
      * implementation that was assigned at build time.
      */
      private static Properties createDefaultProperties()
      {
          final String path = 
            REPOSITORY_GROUP_NAME + "/" 
            + REPOSITORY_APPLICATION_NAME 
            + ".meta";
  
          try
          {
              Properties properties = new Properties();
              ClassLoader classloader = 
                Thread.currentThread().getContextClassLoader();
              InputStream input = classloader.getResourceAsStream( path );
              if( input == null ) 
              {
                  final String error = 
                    "Missing resource: [" + path + "]";
                  throw new Error( error );
              }
              properties.load( input ) ;
              return properties;
          }
          catch ( Throwable e )
          {
              final String error = 
                "Internal error. " 
                + "Unable to locate the standard repository impl directive from the 
path: " 
                + path;
              RepositoryException re = new RepositoryException( error, e );
              re.printStackTrace( System.err ) ;
              return null;
          }
     }
          
      // ------------------------------------------------------------------------
      
      /** base property key for the urls of the required jars */
      public static final String URLS_BASE = "url" ;
      /** factory delegate implementation class name key */
      public static final String FACTORY_KEY = "factory" ;
  
      /** the properties file containing seed information */
      public static final String PROPS = "repository.properties" ;
  
      /** repository loader's bootstrap properties */
      private static Properties s_props = null ;
      
      /** the delegate repository factory instantiated */
      private RepositoryFactory m_delegate = null ;
  
      
      // ------------------------------------------------------------------------
      // C O N S T R U C T O R S
      // ------------------------------------------------------------------------
      
      
      /**
       * Creates a repository which in turn instantiates the default Repository 
       * factory implementation and delegates calls to it.
       * 
       * @throws RepositoryException
       */
      public InitialRepositoryFactory() 
          throws RepositoryException
      {
          this( REFERENCE ) ;
      }
  
      /**
       * Creates a repository which in turn instantiates a Repository 
       * factory implementation specified by an artifact descriptor and the 
       * implementation factory's class name.  This factory delegates 
       * calls to the implementation factory once it is created.
       * 
       * @throws RepositoryException
       */
      public InitialRepositoryFactory( String[] repositories ) 
          throws RepositoryException
      {
           this( REFERENCE, repositories );
      }
      
      
      /**
       * Creates a repository which in turn instantiates a Repository 
       * factory implementation specified by an artifact descriptor and the 
       * implementation factory's class name.  This factory delegates 
       * calls to the implementation factory once it is created.
       * 
       * @throws RepositoryException
       */
      public InitialRepositoryFactory( ArtifactReference reference ) 
          throws RepositoryException
      {
           this( reference, DEFAULT_REPOSITORIES );
      }
  
      /**
       * Creates a repository which in turn instantiates a Repository 
       * factory implementation specified by an artifact descriptor and the 
       * implementation factory's class name.  This factory delegates 
       * calls to the implementation factory once it is created.
       * 
       * @throws RepositoryException
       */
      public InitialRepositoryFactory( ArtifactReference reference, String[] 
repositories ) 
          throws RepositoryException
      {
           this( new ApplicationDirective( reference, repositories ) );
      }
  
      /**
       * Creates a repository which in turn instantiates a Repository 
       * factory implementation specified by an artifact descriptor and the 
       * implementation factory's class name.  This factory delegates 
       * calls to the implementation factory once it is created.
       * 
       * @throws RepositoryException
       */
      public InitialRepositoryFactory( ApplicationDirective app ) 
          throws RepositoryException
      {
           if( app == null ) throw new NullPointerException( "app" );
  
          /* 
           * Create the temporary directory to pull down files into
           */
          String l_userHome = System.getProperty( "user.home" ) ;
          File l_tmpDir = new File( l_userHome, ".bootstrap" ) ;
          if ( ! l_tmpDir.exists() )
          {
              l_tmpDir.mkdirs() ;
          }
          
          /*
           * Build the url to access the properties of the implementation artifact
           * which is default mechanism dependent.
           */
  
          JarDescriptor implementation = app.getJarDescriptor();
          String[] repositories = app.getDefaultRepositories();
  
          Properties l_props = RepositoryUtils.getProperties( repositories, 
implementation ) ;
          Attributes l_attrs = RepositoryUtils.getAsAttributes( l_props ) ;
          
          /*
           * Download every dependency referenced by the implementation into the
           * temporary cache to build the repository classloader with.
           */
          ArrayList l_urlList = new ArrayList() ;
          JarDescriptor l_dep = null;
          String l_spec = null;
          File l_targetFile = null;
          try
          {
              // TODO:
              // If the key that is supplied here is does not have a value we get null 
              // back instead of an empty list
  
              NamingEnumeration l_list = l_attrs.get( "avalon.dependency" ).getAll() ;
              while ( l_list.hasMore() )
              {
                  l_spec = ( String ) l_list.next() ;
                  l_dep = new JarDescriptor( l_spec ) ;
                  
                  StringBuffer l_target = 
                    new StringBuffer( l_tmpDir.toString() ) ;
                  
                  if ( '/' != l_target.charAt( l_target.length() - 1 ) )
                  {
                      l_target.append( '/' ) ;
                  }
                  
                  l_target.append( l_dep.getRootRelativePath() ) ;
                  l_targetFile = new File( l_target.toString() ) ;
  
                  cacheArtifact( 
                    l_dep, repositories,
                    l_targetFile, true ) ;
                  l_urlList.add( l_targetFile.toURL() ) ;
              }
          }
          catch ( NamingException e )
          {
              final String error = 
                "Unable to construct attributes for the implementation reference: [" 
                + implementation + "]."; 
              throw new RepositoryException( error, e ) ;
          }
          catch ( ParseException e )
          {    
              final String error = 
                "Unable to parse a dependency specification [" + l_spec 
                + "] in the implementation reference: [" + implementation + "]."; 
              throw new RepositoryException( error, e ) ;
          }
          catch ( MalformedURLException e )
          {
              final String error = 
                "Unable to create a url to a local file [" + l_targetFile
                + "] for the dependency [" + l_spec 
                + "] from the implementation reference: [" + implementation + "]."; 
              throw new RepositoryException( "Bad url: " + l_dep, e ) ;
          }
          catch ( Exception e )
          {
              final String error = 
                "Unable to download dependent artifact[" + l_spec 
                + "] for the implementation reference: [" + implementation + "]."; 
              throw new RepositoryException( error, e ) ;
          }
  
          //
          // add the actual implementation jar file
          //
  
          try
          {
              StringBuffer target = new StringBuffer( l_tmpDir.toString() ) ;
              if ( '/' != target.charAt( target.length() - 1 ) ) target.append( '/' ) ;
              target.append( implementation.getRootRelativePath() ) ;
              File file = new File( target.toString() ) ;
              cacheArtifact( implementation, repositories, file, true ) ;
              l_urlList.add( file.toURL() ) ;
          }
          catch( Throwable e )
          {
              final String error = 
                "Unable to download target artifact[" + implementation + "]."; 
              throw new RepositoryException( error, e ) ;
          }
  
          //
          // create the classloader to load the implementation stack
          //
          
          ClassLoader l_loader = new URLClassLoader( 
             (URL[]) l_urlList.toArray( new URL [0] ), 
             Thread.currentThread().getContextClassLoader() ) ;
  
          //
          // load the actual repository implementation 
          //
          
          try
          {
              Class l_clazz = l_loader.loadClass( DEFAULT_FACTORY ) ;
              m_delegate = ( RepositoryFactory ) l_clazz.newInstance() ;
          }
          catch( IllegalAccessException e )
          {
              throw new RepositoryException( "Could not default constructor on: " 
                  + DEFAULT_FACTORY , e ) ;
          }
          catch( InstantiationException e )
          {
              throw new RepositoryException( 
                  "Could not instantiate the factory class: " + DEFAULT_FACTORY, e ) ;
          }
          catch( ClassNotFoundException e )
          {
              printClassLoader( l_loader );
              throw new RepositoryException( "Could not find the factory class: " 
                  + DEFAULT_FACTORY, e ) ;
          }
      }
  
      private void printClassLoader( ClassLoader loader )
      {
          if( loader == null ) return;
          if( loader instanceof URLClassLoader )
          {
              printURLClassLoader( (URLClassLoader) loader );
          }
      }
  
      private void printURLClassLoader( URLClassLoader loader )
      {
          System.out.println( "  " );
          URL[] urls = loader.getURLs();
          for( int i=0; i<urls.length; i++ )
          {
              System.out.println( "  " + urls[i] );
          }
  
          ClassLoader parent = loader.getParent();
          printClassLoader( parent );
      }
  
      // ------------------------------------------------------------------------
      // RepositoryFactory Implementations
      // ------------------------------------------------------------------------
      
      /**
       * Factory method that creates a repository by calling the delegate factory.
       * 
       * @param context a repository creation context
       * @return the newly created repository
       * @throws RepositoryException if there is a failure while creating the repo
       * @see org.apache.avalon.repository.RepositoryFactory
       * create(org.apache.avalon.repository.RepositoryContext)
       */
      public Repository create( RepositoryContext context ) 
          throws RepositoryException 
      {
          return m_delegate.create( context ) ;
      }
  
      
      /**
       * Factory method that creates a default repository configuration bean 
       * by calling the delegate factory.
       * 
       * @see org.apache.avalon.repository.RepositoryFactory#getDefaultContext()
       */
      public RepositoryContext getDefaultContext() throws RepositoryException
      {
          return m_delegate.getDefaultContext() ;
      }
      
      
      // ------------------------------------------------------------------------
      // Utility Methods
      // ------------------------------------------------------------------------
  
      
      /**
       * Attempts to download and cache a remote artifact trying a set of remote
       * repositories.  The operation is not fail fast and so it keeps trying if
       * the first repository does not have the artifact in question.
       * 
       * @param a_artifact the artifact to retrieve and cache
       * @param a_destFile where to store it locally in the cache
       * @param a_useTimestamp whether to check the modified timestamp on the
       *      <code>destinationFile</code> against the remote <code>source</code>
       * @return TRUE if the file was updated else FALSE
       */
      public static boolean cacheArtifact( ArtifactDescriptor a_artifact, 
          File a_destFile, boolean a_useTimestamp ) 
          throws RepositoryException
      {
          return cacheArtifact( a_artifact, DEFAULT_REPOSITORIES, a_destFile, 
a_useTimestamp ) ;
      }
      
      
      /**
       * Attempts to download and cache a remote artifact trying a set of remote
       * repositories.  The operation is not fail fast and so it keeps trying if
       * the first repository does not have the artifact in question.
       * 
       * @param a_artifact the artifact to retrieve and cache
       * @param a_repos the remote repositories to try to download from 
       * @param a_destFile where to store it locally in the cache
       * @param a_useTimestamp whether to check the modified timestamp on the
       *      <code>destinationFile</code> against the remote <code>source</code>
       * @return TRUE if the file was updated else FALSE
       */
      public static boolean cacheArtifact( ArtifactDescriptor a_artifact, 
          String [] a_repos, File a_destFile, boolean a_useTimestamp ) 
          throws RepositoryException
      {
          boolean l_updated = false ;
          Exception l_cause = null ;
          
          /*
           * Don't fail fast - keep trying until we get something.
           */
          for ( int ii = 0; ii < a_repos.length; ii++ )
          {
              try 
              {
                  String l_url = a_artifact.getURL( a_repos[ii] ) ;
                  l_updated = getTempFile( l_url, a_destFile, a_useTimestamp ) ;
                  return l_updated ;
              }
              catch ( Exception e )
              {
                  l_cause = e ;
              }
          }
          
          if ( null == l_cause )
          {
              throw new RepositoryException( "Failed to download artifact to "
                  + "local cache file " + a_destFile.getAbsolutePath() ) ;
          }
  
          // Should not really execute but it shuts up the compiler
          throw new RepositoryException( "Failed to download artifact to "
              + "local cache file " + a_destFile.getAbsolutePath(), l_cause ) ;
      }
  
      
      /**
       * Retrieve a remote file.  Returns true if the file was successfully
       * retrieved or if it is up to date (when the useTimestamp flag is set).
       * 
       * Moved here from HttpController.
       *
       * @param a_url the of the file to retrieve
       * @param a_destFile where to store it
       * @param a_useTimestamp whether to check the modified timestamp on the
       *      <code>destinationFile</code> against the remote <code>source</code>
       * @return TRUE if the file was updated else FALSE
       */
      public static boolean getTempFile( String a_url, File a_destFile,
          boolean a_useTimestamp ) throws Exception
      {
          URL l_source = null ; 
          String l_username = null ;
          String l_password = null ;
  
          // We want to be able to deal with Basic Auth where the username
          // and password are part of the URL. An example of the URL string
          // we would like to be able to parse is like the following:
          //
          // http://username:[EMAIL PROTECTED]
  
          int l_atIdx = a_url.indexOf( "@" ) ;
          if ( l_atIdx > 0 )
          {
              String s = a_url.substring( 7, l_atIdx ) ;
              int l_colonIdx = s.indexOf( ":" ) ;
              l_username = s.substring( 0, l_colonIdx ) ;
              l_password = s.substring( l_colonIdx + 1 ) ;
              l_source = new URL( "http://"; + a_url.substring( l_atIdx + 1 ) ) ;
          }
          else
          {
              l_source = new URL( a_url ) ;
          }
  
          //set the timestamp to the file date.
          long l_timestamp = 0 ;
          boolean l_hasTimestamp = false ;
          if ( a_useTimestamp && a_destFile.exists() )
          {
              l_timestamp = a_destFile.lastModified() ;
              l_hasTimestamp = true ;
          }
  
          //set up the URL connection
          URLConnection l_connection = l_source.openConnection() ;
  
          //modify the headers
          //NB: things like user authentication could go in here too.
          if ( a_useTimestamp && l_hasTimestamp )
          {
              l_connection.setIfModifiedSince( l_timestamp ) ;
          }
  
          //connect to the remote site (may take some time)
          l_connection.connect() ;
          //next test for a 304 result (HTTP only)
          if ( l_connection instanceof HttpURLConnection )
          {
              HttpURLConnection l_httpConnection = 
                  ( HttpURLConnection ) l_connection ;
              
              if ( l_httpConnection.getResponseCode() == 
                      HttpURLConnection.HTTP_NOT_MODIFIED )
              {
                  return false ;
              }
              
              // test for 401 result (HTTP only)
              if ( l_httpConnection.getResponseCode() == 
                      HttpURLConnection.HTTP_UNAUTHORIZED )
              {
                  throw new Exception( "Not authorized." ) ;
              }
          }
  
          // REVISIT: at this point even non HTTP connections may support the
          // if-modified-since behaviour - we just check the date of the
          // content and skip the write if it is not newer.
          // Some protocols (FTP) dont include dates, of course.
  
          InputStream l_in = null ;
          for ( int ii = 0; ii < 3; ii++ )
          {
              try
              {
                  l_in = l_connection.getInputStream() ;
                  break ;
              }
              catch ( IOException ex )
              {
                  // do nothing
              }
          }
          if ( l_in == null )
          {
              final String error = 
                "Connection returned a null input stream: " + a_url ;
              throw new IOException( error ) ;
          }
  
          File parent = a_destFile.getParentFile() ;
          parent.mkdirs() ;
  
          FileOutputStream l_out = new FileOutputStream( a_destFile ) ;
  
          byte[] buffer = new byte[100 * 1024] ;
          int length ;
  
          System.out.print( "Source: " + l_source + "\n") ;
          while ( ( length = l_in.read( buffer ) ) >= 0 )
          {
              l_out.write( buffer, 0, length ) ;
              System.out.print( "." ) ;
          }
  
          System.out.println( "" ) ;
          l_out.close() ;
          l_in.close() ;
  
          // if (and only if) the use file time option is set, then the
          // saved file now has its timestamp set to that of the downloaded
          // file
  
          if ( a_useTimestamp )
          {
              long l_remoteTimestamp = l_connection.getLastModified() ;
  
              if ( l_remoteTimestamp != 0 )
              {
                  long l_modifiedTime ;
  
                  if ( l_remoteTimestamp  < 0 )
                  {
                      l_modifiedTime = System.currentTimeMillis() ;
                  }
                  else
                  {
                      l_modifiedTime = l_remoteTimestamp  ;
                  }
  
                  a_destFile.setLastModified( l_modifiedTime ) ;
                  return true ;
              }
          }
          
          return true ;
      }
  }
  
  
  
  1.1                  
avalon-sandbox/repository/main/src/java/org/apache/avalon/repository/package.html
  
  Index: package.html
  ===================================================================
  
  <body>
  <p>
  The repository package contains an contract for abstract repository services.
  </p>
  
  </body>
  
  
  

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

Reply via email to