From 339e3993e51237d0ad0980622e93bec31fc750df Mon Sep 17 00:00:00 2001 From: Peter Donald Date: Mon, 26 Nov 2001 11:11:44 +0000 Subject: [PATCH] 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 --- proposal/myrmidon/build.xml | 12 +- .../components/deployer/DefaultDeployer.java | 119 ++++++++++++++++-- .../components/deployer/Resources.properties | 7 ++ .../libs/selftest/ExtensionsTest.java | 27 ++++ .../extension1/ExtensionsLoadedClass.java | 24 ++++ .../myrmidon/src/make/primitive-tests.ant | 6 +- proposal/myrmidon/src/make/sample.ant | 4 +- .../src/manifest/selftest-ant-descriptor.xml | 1 + .../src/manifest/selftest-extension1.mf | 9 ++ proposal/myrmidon/src/manifest/selftest.mf | 11 ++ 10 files changed, 204 insertions(+), 16 deletions(-) create mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/ExtensionsTest.java create mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/extension1/ExtensionsLoadedClass.java create mode 100644 proposal/myrmidon/src/manifest/selftest-extension1.mf create mode 100644 proposal/myrmidon/src/manifest/selftest.mf diff --git a/proposal/myrmidon/build.xml b/proposal/myrmidon/build.xml index c2d72d4d9..aa278c107 100644 --- a/proposal/myrmidon/build.xml +++ b/proposal/myrmidon/build.xml @@ -164,13 +164,22 @@ Legal: - + + + + + + @@ -209,6 +218,7 @@ Legal: + diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java index dfb5b2ec2..735c0aa6e 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java @@ -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 ) diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Resources.properties index 986034c78..3138fa3bc 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Resources.properties @@ -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. \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/ExtensionsTest.java b/proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/ExtensionsTest.java new file mode 100644 index 000000000..2d320e67a --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/ExtensionsTest.java @@ -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 Peter Donald + */ +public class ExtensionsTest + extends AbstractTask +{ + public void execute() + throws TaskException + { + ExtensionsLoadedClass.doSomething(); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/extension1/ExtensionsLoadedClass.java b/proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/extension1/ExtensionsLoadedClass.java new file mode 100644 index 000000000..7da9e8536 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/libs/selftest/extension1/ExtensionsLoadedClass.java @@ -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 Peter Donald + */ +public class ExtensionsLoadedClass +{ + public static void doSomething() + { + System.out.println( "This was loaded via an extension - yea!" ); + } +} diff --git a/proposal/myrmidon/src/make/primitive-tests.ant b/proposal/myrmidon/src/make/primitive-tests.ant index fe030c785..356efa619 100644 --- a/proposal/myrmidon/src/make/primitive-tests.ant +++ b/proposal/myrmidon/src/make/primitive-tests.ant @@ -41,7 +41,7 @@ Legal: - + @@ -72,4 +72,8 @@ Legal: + + + + \ No newline at end of file diff --git a/proposal/myrmidon/src/make/sample.ant b/proposal/myrmidon/src/make/sample.ant index 691f62ecd..7e9e785d0 100644 --- a/proposal/myrmidon/src/make/sample.ant +++ b/proposal/myrmidon/src/make/sample.ant @@ -6,7 +6,7 @@ Sample build file Authors: - Peter Donald + Peter Donald Legal: Copyright (c) 2000 The Apache Software Foundation. All Rights Reserved. @@ -20,7 +20,7 @@ Legal: - + diff --git a/proposal/myrmidon/src/manifest/selftest-ant-descriptor.xml b/proposal/myrmidon/src/manifest/selftest-ant-descriptor.xml index c6ce854c2..4232cd70e 100644 --- a/proposal/myrmidon/src/manifest/selftest-ant-descriptor.xml +++ b/proposal/myrmidon/src/manifest/selftest-ant-descriptor.xml @@ -6,5 +6,6 @@ + \ No newline at end of file diff --git a/proposal/myrmidon/src/manifest/selftest-extension1.mf b/proposal/myrmidon/src/manifest/selftest-extension1.mf new file mode 100644 index 000000000..c58bdb884 --- /dev/null +++ b/proposal/myrmidon/src/manifest/selftest-extension1.mf @@ -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 + diff --git a/proposal/myrmidon/src/manifest/selftest.mf b/proposal/myrmidon/src/manifest/selftest.mf new file mode 100644 index 000000000..a1998654a --- /dev/null +++ b/proposal/myrmidon/src/manifest/selftest.mf @@ -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