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]