You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by mc...@apache.org on 2004/02/17 12:06:17 UTC
cvs commit: avalon/repository/main/src/java/org/apache/avalon/repository/main DefaultInitialContextFactory.java AbstractBuilder.java DefaultBuilder.java DefaultInitialContext.java
mcconnell 2004/02/17 03:06:17
Modified: repository/main/src/java/org/apache/avalon/repository/main
AbstractBuilder.java DefaultBuilder.java
DefaultInitialContext.java
Added: repository/main/src/java/org/apache/avalon/repository/main
DefaultInitialContextFactory.java
Log:
Add support for an initial context factory that exposes the application root directory. This provides sufficent info for dealing with properties management with an IDE.
Revision Changes Path
1.7 +2 -2 avalon/repository/main/src/java/org/apache/avalon/repository/main/AbstractBuilder.java
Index: AbstractBuilder.java
===================================================================
RCS file: /home/cvs/avalon/repository/main/src/java/org/apache/avalon/repository/main/AbstractBuilder.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- AbstractBuilder.java 31 Jan 2004 13:29:50 -0000 1.6
+++ AbstractBuilder.java 17 Feb 2004 11:06:16 -0000 1.7
@@ -86,7 +86,7 @@
* </ul>
*
* @param classloader the classloader
- * @param factory the the factory classname
+ * @param clazz the the factory class
* @param context the inital repository context
* @return the instantiated factory
* @exception RepositoryException if a factory creation error occurs
1.13 +2 -2 avalon/repository/main/src/java/org/apache/avalon/repository/main/DefaultBuilder.java
Index: DefaultBuilder.java
===================================================================
RCS file: /home/cvs/avalon/repository/main/src/java/org/apache/avalon/repository/main/DefaultBuilder.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- DefaultBuilder.java 31 Jan 2004 13:29:50 -0000 1.12
+++ DefaultBuilder.java 17 Feb 2004 11:06:16 -0000 1.13
@@ -314,7 +314,7 @@
* @return the delegate factory
* @exception RepositoryRuntimeException if the declared class does
* not implement the factory interface
- * @see getFactoryClass
+ * @see #getFactoryClass
*/
public Factory getFactory()
{
1.18 +112 -29 avalon/repository/main/src/java/org/apache/avalon/repository/main/DefaultInitialContext.java
Index: DefaultInitialContext.java
===================================================================
RCS file: /home/cvs/avalon/repository/main/src/java/org/apache/avalon/repository/main/DefaultInitialContext.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- DefaultInitialContext.java 2 Feb 2004 00:41:24 -0000 1.17
+++ DefaultInitialContext.java 17 Feb 2004 11:06:16 -0000 1.18
@@ -234,6 +234,8 @@
/**
* Creates an initial repository context.
*
+ * @param base the base working directory
+ * @param loader the parent classloader
* @param artifact an artifact referencing the default implementation
* @param cache the cache directory
* @param hosts a set of initial remote repository addresses
@@ -244,14 +246,8 @@
throws RepositoryException
{
m_base = setupBaseDirectory( base );
- Properties avalonSystem =
- getLocalProperties( getAvalonHome(), AVALON_PROPERTIES );
- Properties avalonHome =
- getLocalProperties( USER_HOME, AVALON_PROPERTIES );
- Properties avalonWork =
- getLocalProperties( m_base, AVALON_PROPERTIES );
- m_cache = setupCache( cache, avalonSystem, avalonHome, avalonWork );
- m_hosts = setupHosts( hosts, avalonSystem, avalonHome, avalonWork );
+ m_cache = setupCache( cache, base );
+ m_hosts = setupHosts( hosts, base );
Artifact implementation = setupImplementation( artifact );
ClassLoader parent = setupClassLoader( loader );
@@ -326,6 +322,88 @@
throw new RepositoryException( buffer.toString(), e );
}
}
+
+ /**
+ * Creates an initial repository context.
+ *
+ * @param artifact an artifact referencing the default implementation
+ * @param cache the cache directory
+ * @param hosts a set of initial remote repository addresses
+ * @throws RepositoryException if an error occurs during establishment
+ */
+ DefaultInitialContext(
+ ClassLoader parent, Artifact artifact, File base, File cache, String[] hosts )
+ throws RepositoryException
+ {
+ if( null == base ) throw new NullPointerException( "base" );
+ if( null == parent ) throw new NullPointerException( "parent" );
+ if( null == artifact ) throw new NullPointerException( "artifact" );
+ if( null == cache ) throw new NullPointerException( "cache" );
+ if( null == hosts ) throw new NullPointerException( "hosts" );
+
+ m_base = base;
+ m_cache = cache;
+ m_hosts = hosts;
+
+ Attributes attributes = loadAttributes( m_cache, m_hosts, artifact );
+ FactoryDescriptor descriptor = new FactoryDescriptor( attributes );
+ String factory = descriptor.getFactory();
+ if( null == factory )
+ {
+ final String error =
+ "Required property 'avalon.artifact.factory' not present in artifact: "
+ + artifact + " under the active cache: [" + m_cache + "] using the "
+ + "attribute sequence: " + attributes;
+ throw new IllegalArgumentException( error );
+ }
+
+ //
+ // Grab all of the dependents in one hit because this is
+ // the implementation so we can ignore api/spi spread.
+ //
+
+ Artifact[] dependencies = descriptor.getDependencies();
+
+ int n = dependencies.length;
+ URL[] urls = new URL[ n + 1];
+ for( int i=0; i<n; i++ )
+ {
+ urls[i] = LoaderUtils.getResource(
+ dependencies[i], m_hosts, m_cache, true );
+ }
+
+ urls[ n ] = LoaderUtils.getResource(
+ artifact, m_hosts, m_cache, true );
+
+ //
+ // create the classloader
+ //
+
+ ClassLoader classloader = new URLClassLoader( urls, parent );
+ Class clazz = loadFactoryClass( classloader, factory );
+
+ //
+ // load the actual repository implementation
+ //
+
+ try
+ {
+ m_factory = createDelegate( classloader, clazz, this );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unable to establish a factory for the supplied artifact:";
+ StringBuffer buffer = new StringBuffer( error );
+ buffer.append( "\n artifact: " + artifact );
+ buffer.append( "\n build: " + descriptor.getBuild() );
+ buffer.append( "\n factory: " + descriptor.getFactory() );
+ buffer.append( "\n source: "
+ + clazz.getProtectionDomain().getCodeSource().getLocation() );
+ buffer.append( "\n cache: " + m_cache );
+ throw new RepositoryException( buffer.toString(), e );
+ }
+ }
// ------------------------------------------------------------------------
// InitialContext
@@ -395,7 +473,7 @@
}
/**
- * Install a block archive into the repository.
+ * Install a block archive into the repository cache.
* @param url the block archive url
* @return the block manifest
*/
@@ -567,18 +645,16 @@
return DefaultInitialContext.class.getClassLoader();
}
- private File setupCache(
- File file, Properties system, Properties home, Properties work )
+ private File setupCache( File cache, File base )
{
- if( null != file ) return file;
- return setupDefaultCache( system, home, work );
+ if( null != cache ) return cache;
+ return setupDefaultCache( base );
}
- private String[] setupHosts(
- String[] hosts, Properties system, Properties home, Properties work )
+ private String[] setupHosts( String[] hosts, File base )
{
if( null != hosts ) return RepositoryUtils.getCleanPaths( hosts );
- return setupDefaultHosts( system, home, work );
+ return setupDefaultHosts( base );
}
private Artifact setupImplementation( Artifact artifact )
@@ -622,7 +698,8 @@
private static Artifact getDefaultImplementation()
{
Properties properties = createDefaultProperties();
- String spec = properties.getProperty( "avalon.repository.implementation" );
+ String spec = properties.getProperty(
+ InitialContext.IMPLEMENTATION_KEY );
if( null == spec )
{
final String error =
@@ -638,23 +715,19 @@
return getBaseDirectory();
}
- private String[] setupDefaultHosts(
- Properties system, Properties home, Properties work )
+ private String[] setupDefaultHosts( File base )
{
- String systemValue = system.getProperty( HOSTS_KEY );
- String homeValue = home.getProperty( HOSTS_KEY, systemValue );
- String workValue = work.getProperty( HOSTS_KEY, homeValue );
+ String homeValue = getUserProperties().getProperty( HOSTS_KEY );
+ String workValue = getWorkProperties( base ).getProperty( HOSTS_KEY, homeValue );
String value = System.getProperty( HOSTS_KEY , workValue );
if( null == value ) return DEFAULT_INITIAL_HOSTS;
return expandHosts( value );
}
- private static File setupDefaultCache(
- Properties system, Properties home, Properties work )
+ private static File setupDefaultCache( File base )
{
- String systemValue = system.getProperty( CACHE_KEY );
- String homeValue = home.getProperty( CACHE_KEY, systemValue );
- String workValue = work.getProperty( CACHE_KEY, homeValue );
+ String homeValue = getUserProperties().getProperty( CACHE_KEY );
+ String workValue = getWorkProperties( base ).getProperty( CACHE_KEY, homeValue );
String value = System.getProperty( CACHE_KEY , workValue );
if( null != value ) return new File( value );
return getDefaultCache();
@@ -675,7 +748,7 @@
return new File( System.getProperty( "user.dir" ) );
}
- private Properties getLocalProperties(
+ private static Properties getLocalProperties(
File dir, String filename )
{
Properties properties = new Properties();
@@ -705,5 +778,15 @@
list.add( tokenizer.nextToken() );
}
return (String[]) list.toArray( new String[0] );
+ }
+
+ private static Properties getUserProperties()
+ {
+ return getLocalProperties( USER_HOME, AVALON_PROPERTIES );
+ }
+
+ private static Properties getWorkProperties( File base )
+ {
+ return getLocalProperties( base, AVALON_PROPERTIES );
}
}
1.1 avalon/repository/main/src/java/org/apache/avalon/repository/main/DefaultInitialContextFactory.java
Index: DefaultInitialContextFactory.java
===================================================================
/*
* Copyright 2004 Apache Software Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.avalon.repository.main;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Constructor;
import java.lang.NoSuchMethodException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLClassLoader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.JarURLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.text.ParseException;
import java.util.StringTokenizer;
import java.util.jar.Manifest;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attributes;
import org.apache.avalon.repository.Artifact;
import org.apache.avalon.repository.Repository;
import org.apache.avalon.repository.RepositoryException;
import org.apache.avalon.repository.RepositoryRuntimeException;
import org.apache.avalon.repository.meta.FactoryDescriptor;
import org.apache.avalon.repository.provider.Factory;
import org.apache.avalon.repository.provider.InitialContext;
import org.apache.avalon.repository.provider.InitialContextFactory;
import org.apache.avalon.repository.provider.Builder;
import org.apache.avalon.repository.util.LoaderUtils;
import org.apache.avalon.repository.util.RepositoryUtils;
import org.apache.avalon.util.env.Env;
import org.apache.avalon.util.env.EnvAccessException;
import org.apache.avalon.util.exception.ExceptionHelper;
import org.apache.avalon.util.defaults.DefaultsBuilder;
/**
* A utility class used to establish a new {@link InitialContext}
* instance. An initial context is normally created by simply
* instantiating the factory using a application key and a working
* directory.
*
* <pre>
* final String key = "demo";
* final File work = new File( System.getProperty( "user.dir" ) );
* final InitialContextFactory factory =
* new DefaultInitialContextFactory( key, work );
* InitialContext context = factory.createInitialContext();
* </pre>
*
* @author <a href="mailto:mcconnell@apache.org">Stephen McConnell</a>
* @version $Revision: 1.1 $
*/
public class DefaultInitialContextFactory implements InitialContextFactory
{
//------------------------------------------------------------------
// private static
//------------------------------------------------------------------
/**
* The name of a properties resource contained within the repository
* bootstrap jar file. Property values contained in this resource
* consitute the most primative static default values.
*/
private static final String AVALON_PROPERTIES = "avalon.properties";
//------------------------------------------------------------------
// immutable state
//------------------------------------------------------------------
private final String m_key;
private final File m_work;
private final DefaultsBuilder m_defaults;
private final Properties m_properties;
//------------------------------------------------------------------
// mutable state
//------------------------------------------------------------------
private File m_cache;
private Artifact m_artifact;
private ClassLoader m_classloader;
private String[] m_hosts;
// ------------------------------------------------------------------------
// constructor
// ------------------------------------------------------------------------
/**
* <p>Creates an initial repository context factory. The supplied
* key is used to establish the application root directory and
* property files at application, user and working directory
* levels. A key such as 'merlin' will be transformed to the
* environment symbol 'MERLIN_HOME' (i.e. uppercase of key plus
* _HOME) and resolved to a value. If the symbol is undefined,
* the application home directory defaults to a file path
* ${user.home}/.[key] (so for example, if MERLIN_HOME is
* undefined the default application home for Merlin is
* ${user.home}/.merlin. Based on the application root directory,
* a set of property files with the name [key].properties are
* resolved from the following locations:</p>
*
* <ul>
* <li>the current working directory</li>
* <li>user's home directory</li>
* <li>application home directory</li>
* </ul>
*
* <p>The order in which properties are evaluated in in accordance
* the above list. The current working directory properties take
* precedence over properties defined in the user's home directory
* which in turn take precedence over properties defined under the
* application home directory. System properties take precedence
* over all properties.</p>
*
* @param key the application key
* @param work the working directory
* @throws IOException if an error occurs during establishment
*/
public DefaultInitialContextFactory( String key, File work )
throws IOException
{
m_key = key;
m_work = work;
m_defaults = new DefaultsBuilder( key, work );
Properties defaults = getDefaultProperties();
m_properties =
m_defaults.getConsolidatedProperties(
defaults,
KEYS );
String spec = m_properties.getProperty(
InitialContext.IMPLEMENTATION_KEY );
if( null != spec )
{
m_artifact = Artifact.createArtifact( spec );
}
else
{
final String error =
"Required implementation key ["
+ InitialContext.IMPLEMENTATION_KEY
+ "] not found.";
throw new IllegalStateException( error );
}
}
// ------------------------------------------------------------------------
// InitialContextFactory
// ------------------------------------------------------------------------
/**
* Set the parent classloader. If not defined, the default
* classloader is the classloader holding this class.
*
* @param classloader the parent classloader
*/
public void setParentClassLoader( ClassLoader classloader )
{
m_classloader = classloader;
}
/**
* The initial context factory support the establishment of an
* initial context which is associated with a repository cache
* manager implementation. A client can override the default
* repository cache manager implementation by declaring an
* artifact referencing a compliant factory (not normally
* required).
*
* @param artifact the repository cache manager artifact
*/
public void setImplementation( Artifact artifact )
{
m_artifact = artifact;
}
/**
* The cache directory is the directory into which resources
* such as jar files are loaded by a repository cache manager.
*
* @param cache the repository cache directory
*/
public void setCacheDirectory( File cache )
{
m_cache = cache;
}
/**
* Set the initial hosts to be used by a repository cache manager
* implementation and the initial context implementation when
* resolving dependent resources. If is resource is not present
* in a local cache, remote hosts are checked in the order presented
* in the supplied list. A host may be a file url or a http url.
*
* @param hosts a sequence of remote host urls
*/
public void setHosts( String[] hosts )
{
m_hosts = hosts;
}
/**
* Creation of an inital context based on the system and working
* directory, parent classloader, repository cache manager implementation
* artifact, cache directory, and remote hosts sequence supplied to the
* factory.
*
* @return a new initial context
*/
public InitialContext createInitialContext()
{
try
{
return new DefaultInitialContext(
getParentClassLoader(),
getImplementation(),
getWorkingDirectory(),
getCacheDirectory(),
getHosts() );
}
catch( Throwable e )
{
final String error =
"Could not create initial context.";
throw new RepositoryRuntimeException( error, e );
}
}
/**
* Return the home directory value direved from the application key.
* @return the home directory.
*/
public File getHomeDirectory()
{
return m_defaults.getHomeDirectory();
}
/**
* Return the working directory value.
* @return the working directory.
*/
public File getWorkingDirectory()
{
return m_work;
}
/**
* Return the parent classloader. The default classloader returned
* from this operation is the classloader containing this class.
*
* @return the parent classloader
*/
public ClassLoader getParentClassLoader()
{
if( null != m_classloader ) return m_classloader;
return DefaultInitialContext.class.getClassLoader();
}
/**
* Return the implementation artifact. If not overriden, a default
* artifact referencing avalon-repository-impl will be returned.
*
* @return the implementation artifact
*/
public Artifact getImplementation()
{
return m_artifact;
}
/**
* Return the assigned or default cache directory. If undefined
* the cache directory shall default to ${avalon.home}/repository.
*
* @return the cache directory
*/
public File getCacheDirectory()
{
if( null != m_cache ) return m_cache;
String value = m_properties.getProperty( InitialContext.CACHE_KEY );
if( null != value ) return new File( value );
return new File( getHomeDirectory(), "repository" );
}
/**
* Return the assigned or default host sequence.
* @return the remote host url sequence
*/
public String[] getHosts()
{
if( null != m_hosts ) return m_hosts;
String value = m_properties.getProperty( InitialContext.HOSTS_KEY );
if( null == value ) return new String[0];
return expandHosts( value );
}
// ------------------------------------------------------------------------
// implementation
// ------------------------------------------------------------------------
private Properties getDefaultProperties() throws IOException
{
Properties properties = new Properties();
ClassLoader classloader =
DefaultInitialContextFactory.class.getClassLoader();
InputStream input =
classloader.getResourceAsStream( AVALON_PROPERTIES );
if( input == null )
{
final String error =
"Missing resource: [" + AVALON_PROPERTIES + "]";
throw new Error( error );
}
properties.load( input );
return properties;
}
private static String[] expandHosts( String arg )
{
ArrayList list = new ArrayList();
StringTokenizer tokenizer = new StringTokenizer( arg, "," );
while( tokenizer.hasMoreTokens() )
{
list.add( tokenizer.nextToken() );
}
return (String[]) list.toArray( new String[0] );
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
For additional commands, e-mail: cvs-help@avalon.apache.org