Browse Source

Added code to allow type libraries to depend upon "Optional Packages" aka "Extensions".

Also add code to seltest type library so that it verifies that classes loaded from extension are available in the same ClassLoader as the tasks.


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270015 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Donald 23 years ago
parent
commit
339e3993e5
10 changed files with 204 additions and 16 deletions
  1. +11
    -1
      proposal/myrmidon/build.xml
  2. +107
    -12
      proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java
  3. +7
    -0
      proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Resources.properties
  4. +27
    -0
      proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/ExtensionsTest.java
  5. +24
    -0
      proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/extension1/ExtensionsLoadedClass.java
  6. +5
    -1
      proposal/myrmidon/src/make/primitive-tests.ant
  7. +2
    -2
      proposal/myrmidon/src/make/sample.ant
  8. +1
    -0
      proposal/myrmidon/src/manifest/selftest-ant-descriptor.xml
  9. +9
    -0
      proposal/myrmidon/src/manifest/selftest-extension1.mf
  10. +11
    -0
      proposal/myrmidon/src/manifest/selftest.mf

+ 11
- 1
proposal/myrmidon/build.xml View File

@@ -164,13 +164,22 @@ Legal:
</zipfileset>
</jar>

<jar jarfile="${build.lib}/selftest.atl" basedir="${build.classes}">
<jar jarfile="${build.lib}/selftest.atl"
basedir="${build.classes}"
manifest="${manifest.dir}/selftest.mf">
<include name="org/apache/myrmidon/libs/selftest/**" />
<exclude name="org/apache/myrmidon/libs/selftest/extension1/**" />
<zipfileset dir="${manifest.dir}" fullpath="META-INF/ant-descriptor.xml">
<include name="selftest-ant-descriptor.xml"/>
</zipfileset>
</jar>

<jar jarfile="${build.lib}/selftest-extension1.jar"
basedir="${build.classes}"
manifest="${manifest.dir}/selftest-extension1.mf">
<include name="org/apache/myrmidon/libs/selftest/extension1/**" />
</jar>

<jar jarfile="${build.lib}/runtime.atl" basedir="${build.classes}">
<include name="org/apache/myrmidon/libs/runtime/**"/>
<zipfileset dir="${manifest.dir}" fullpath="META-INF/ant-descriptor.xml">
@@ -209,6 +218,7 @@ Legal:
<copy todir="${dist.ext}">
<fileset dir="${build.lib}">
<include name="selftest.atl"/>
<include name="selftest-extension1.jar"/>
</fileset>
</copy>



+ 107
- 12
proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java View File

@@ -9,28 +9,37 @@ package org.apache.myrmidon.components.deployer;

import java.io.File;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URLClassLoader;
import java.net.JarURLConnection;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.Manifest;
import java.util.HashMap;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.avalon.excalibur.extension.PackageManager;
import org.apache.avalon.excalibur.extension.OptionalPackage;
import org.apache.avalon.excalibur.extension.Extension;
import org.apache.avalon.excalibur.i18n.ResourceManager;
import org.apache.avalon.excalibur.i18n.Resources;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.configuration.ClassicSAXConfigurationHandler;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.myrmidon.api.Task;
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory;
import org.apache.myrmidon.converter.Converter;
import org.apache.myrmidon.interfaces.converter.ConverterRegistry;
import org.apache.myrmidon.interfaces.deployer.Deployer;
import org.apache.myrmidon.interfaces.deployer.DeploymentException;
import org.apache.myrmidon.interfaces.extensions.ExtensionManager;
import org.apache.myrmidon.interfaces.role.RoleManager;
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory;
import org.apache.myrmidon.interfaces.type.TypeManager;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
@@ -49,9 +58,10 @@ public class DefaultDeployer

private final static String TYPE_DESCRIPTOR = "META-INF/ant-types.xml";

private ConverterRegistry m_converterRegistry;
private TypeManager m_typeManager;
private RoleManager m_roleManager;
private ConverterRegistry m_converterRegistry;
private TypeManager m_typeManager;
private RoleManager m_roleManager;
private PackageManager m_packageManager;

/**
* Retrieve relevent services needed to deploy.
@@ -65,6 +75,10 @@ public class DefaultDeployer
m_converterRegistry = (ConverterRegistry)componentManager.lookup( ConverterRegistry.ROLE );
m_typeManager = (TypeManager)componentManager.lookup( TypeManager.ROLE );
m_roleManager = (RoleManager)componentManager.lookup( RoleManager.ROLE );

final ExtensionManager extensionManager =
(ExtensionManager)componentManager.lookup( ExtensionManager.ROLE );
m_packageManager = new PackageManager( extensionManager );
}

public void initialize()
@@ -75,7 +89,7 @@ public class DefaultDeployer
final XMLReader parser = saxParser.getXMLReader();
//parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false );

final SAXConfigurationHandler handler = new SAXConfigurationHandler();
final ClassicSAXConfigurationHandler handler = new ClassicSAXConfigurationHandler();
parser.setContentHandler( handler );
parser.setErrorHandler( handler );

@@ -106,14 +120,16 @@ public class DefaultDeployer

checkFile( file );

final Deployment deployment = new Deployment( file );
final Configuration descriptor = deployment.getDescriptor();
final URL[] urls = new URL[] { deployment.getURL() };
final URLClassLoader classLoader =
new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() );

try
{
final File[] extensions = getOptionalPackagesFor( file );
final URL[] urls = buildClasspath( file, extensions );
final Deployment deployment = new Deployment( file );
final Configuration descriptor = deployment.getDescriptor();
final URLClassLoader classLoader =
new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() );

deployFromDescriptor( descriptor, classLoader, deployment.getURL() );
}
catch( final DeploymentException de )
@@ -198,6 +214,85 @@ public class DefaultDeployer
}
}

private URL[] buildClasspath( final File file, final File[] dependencies )
throws MalformedURLException
{
final URL[] urls = new URL[ dependencies.length + 1 ];
for( int i = 0; i < dependencies.length; i++ )
{
urls[ i ] = dependencies[ i ].toURL();
}

urls[ dependencies.length ] = file.toURL();

return urls;
}

/**
* Retrieve the files for the optional packages required by
* the specified typeLibrary jar.
*
* @param typeLibrary the typeLibrary
* @return the files that need to be added to ClassLoader
*/
private File[] getOptionalPackagesFor( final File typeLibrary )
throws Exception
{
final URL url = new URL( "jar:" + typeLibrary.getCanonicalFile().toURL() + "!/" );
final JarURLConnection connection = (JarURLConnection)url.openConnection();
final Manifest manifest = connection.getManifest();
final Extension[] available = Extension.getAvailable( manifest );
final Extension[] required = Extension.getRequired( manifest );

if( getLogger().isDebugEnabled() )
{
final String message1 =
REZ.getString( "available-extensions", Arrays.asList( available ) );
getLogger().debug( message1 );
final String message2 =
REZ.getString( "required-extensions", Arrays.asList( required ) );
getLogger().debug( message2 );
}

final ArrayList dependencies = new ArrayList();
final ArrayList unsatisfied = new ArrayList();

m_packageManager.scanDependencies( required,
available,
dependencies,
unsatisfied );

if( 0 != unsatisfied.size() )
{
final int size = unsatisfied.size();
for( int i = 0; i < size; i++ )
{
final Extension extension = (Extension)unsatisfied.get( i );
final Object[] params = new Object[]
{
extension.getExtensionName(),
extension.getSpecificationVendor(),
extension.getSpecificationVersion(),
extension.getImplementationVendor(),
extension.getImplementationVendorId(),
extension.getImplementationVersion(),
extension.getImplementationURL()
};
final String message = REZ.format( "missing.extension", params );
getLogger().warn( message );
}

final String message =
REZ.getString( "unsatisfied.extensions", new Integer( size ) );
throw new Exception( message );
}

final OptionalPackage[] packages =
(OptionalPackage[])dependencies.toArray( new OptionalPackage[ 0 ] );
return OptionalPackage.toFiles( packages );
}

private void deployFromDescriptor( final Configuration descriptor,
final ClassLoader classLoader,
final URL url )


+ 7
- 0
proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Resources.properties View File

@@ -15,3 +15,10 @@ file-is-dir.error=Could not find application archive at {0} as it is a directory
bad-url.error=Unable to form url from file {0}.
bad-parser.error=Error configuring parser.
bad-read.error=Error reading configuration.

available-extensions=The list of available extensions for Type Library includes; {0}
required-extensions=The list of required extensions for Type Library includes; {0}
optional-packages-added=The list of "Optional Packages" added to the Type Library includes; {0}
classpath-entries=The list of classpath entrys for the Type Library includes; {0}
missing.extension=Unable to locate an extension that is required by Type Library.\nExtension Name: {0}\nSpecification Vendor: {1}\nSpecification Version: {2}\nImplementation Vendor: {3}\nImplementation Vendor-Id: {4}\nImplementation Version: {5}\nImplementation URL: {6}
unsatisfied.extensions=Missing {0} extensions and thus can not build ClassLoader for Type Library.

+ 27
- 0
proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/ExtensionsTest.java View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.myrmidon.libs.selftest;

import org.apache.myrmidon.api.AbstractTask;
import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.libs.selftest.extension1.ExtensionsLoadedClass;

/**
* This is to test whether extension is loaded.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class ExtensionsTest
extends AbstractTask
{
public void execute()
throws TaskException
{
ExtensionsLoadedClass.doSomething();
}
}

+ 24
- 0
proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/extension1/ExtensionsLoadedClass.java View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.myrmidon.libs.selftest.extension1;

import org.apache.myrmidon.api.AbstractTask;
import org.apache.myrmidon.api.TaskException;

/**
* This is to test whether extension is loaded.
*
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
*/
public class ExtensionsLoadedClass
{
public static void doSomething()
{
System.out.println( "This was loaded via an extension - yea!" );
}
}

+ 5
- 1
proposal/myrmidon/src/make/primitive-tests.ant View File

@@ -41,7 +41,7 @@ Legal:
<echo message="No tests done here"/>
</target>

<target name="test-target" depends="no-test-target" unless="no-do-tests">
<target name="test-target" depends="no-test-target,extensions-test" unless="no-do-tests">

<echo message="Tests away"/>

@@ -72,4 +72,8 @@ Legal:
</target>

<target name="extensions-test">
<extensions-test/>
</target>

</project>

+ 2
- 2
proposal/myrmidon/src/make/sample.ant View File

@@ -6,7 +6,7 @@
Sample build file

Authors:
Peter Donald <donaldp@apache.org>
Peter Donald <peterp@apache.org>

Legal:
Copyright (c) 2000 The Apache Software Foundation. All Rights Reserved.
@@ -20,7 +20,7 @@ Legal:

<property name="year" value="2000"/>

<target name="main" depends="typedef-test, converterdef-test, datatype-test, namespace-test, ant1-tasklib-test, prim->file-manip" />
<target name="main" depends="typedef-test, converterdef-test, datatype-test, namespace-test, ant1-tasklib-test, prim->file-manip, prim->extensions-test" />

<target name="xp-deployer-test" depends="typedef-test, prim->undefined-task" />



+ 1
- 0
proposal/myrmidon/src/manifest/selftest-ant-descriptor.xml View File

@@ -6,5 +6,6 @@
<task name="conf-test" classname="org.apache.myrmidon.libs.selftest.ConfigurationTest" />
<task name="content-test" classname="org.apache.myrmidon.libs.selftest.ContentTest" />
<task name="file-manip-test" classname="org.apache.myrmidon.libs.selftest.FileManipulationTest" />
<task name="extensions-test" classname="org.apache.myrmidon.libs.selftest.ExtensionsTest" />
</types>
</ant-lib>

+ 9
- 0
proposal/myrmidon/src/manifest/selftest-extension1.mf View File

@@ -0,0 +1,9 @@
Manifest-Version: 1.0
Extension-Name: cornerstone.test.extension
Specification-Title: Avalon Cornerstone Test Extension
Specification-Version: 1.1
Specification-Vendor: Jakarta Apache
Implementation-Vendor-Id: org.apache.avalon
Implementation-Vendor: Apache Avalon Project
Implementation-Version: 1.0.2


+ 11
- 0
proposal/myrmidon/src/manifest/selftest.mf View File

@@ -0,0 +1,11 @@
Manifest-Version: 1.0
Created-By: Apache Avalon Project
Extension-Name: cornerstone.demo.simple
Specification-Title: Avalon Cornerstone SimpleServer Demo Extension
Implementation-Vendor-Id: org.apache.avalon
Implementation-Vendor: Apache Avalon Project
Extension-List: required1
required1-Extension-Name: cornerstone.test.extension
required1-Specification-Version: 1.0
required1-Implementation-Version: 1.0.2
required1-Implementation-Vendor-Id: org.apache.avalon

Loading…
Cancel
Save