diff --git a/proposal/myrmidon/src/java/org/apache/antlib/core/Property.java b/proposal/myrmidon/src/java/org/apache/antlib/core/Property.java index dc058890b..4e16e689c 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/core/Property.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/core/Property.java @@ -54,7 +54,7 @@ public class Property { try { - final TypeFactory typeFactory = getTypeFactory( DataType.ROLE ); + final TypeFactory typeFactory = getTypeFactory( DataType.class ); final DataType value = (DataType)typeFactory.create( children[ i ].getName() ); configure( value, children[ i ] ); setValue( value ); diff --git a/proposal/myrmidon/src/java/org/apache/antlib/runtime/ConverterDef.java b/proposal/myrmidon/src/java/org/apache/antlib/runtime/ConverterDef.java index 69cadb2cd..4df17b7bc 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/runtime/ConverterDef.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/runtime/ConverterDef.java @@ -8,15 +8,12 @@ package org.apache.antlib.runtime; import java.io.File; -import java.net.URL; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.myrmidon.api.AbstractTask; import org.apache.myrmidon.api.TaskException; -import org.apache.myrmidon.converter.Converter; -import org.apache.myrmidon.interfaces.converter.ConverterRegistry; -import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; -import org.apache.myrmidon.interfaces.type.TypeManager; +import org.apache.myrmidon.interfaces.deployer.Deployer; +import org.apache.myrmidon.interfaces.deployer.TypeDeployer; /** * Task to define a converter. @@ -80,15 +77,10 @@ public class ConverterDef try { - final ConverterRegistry converterRegistry = (ConverterRegistry)getService( ConverterRegistry.class ); - converterRegistry.registerConverter( m_classname, m_sourceType, m_destinationType ); - - final URL url = m_lib.toURL(); - final DefaultTypeFactory factory = new DefaultTypeFactory( new URL[]{url} ); - factory.addNameClassMapping( m_classname, m_classname ); - - final TypeManager typeManager = (TypeManager)getService( TypeManager.class ); - typeManager.registerType( Converter.ROLE, m_classname, factory ); + // Locate the deployer, then deploy the converter + final Deployer deployer = (Deployer)getService( Deployer.class ); + final TypeDeployer typeDeployer = deployer.createDeployer( m_lib ); + typeDeployer.deployConverter( m_classname, m_sourceType, m_destinationType ); } catch( final Exception e ) { diff --git a/proposal/myrmidon/src/java/org/apache/antlib/runtime/Facility.java b/proposal/myrmidon/src/java/org/apache/antlib/runtime/Facility.java index 1c0033520..70cfd0301 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/runtime/Facility.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/runtime/Facility.java @@ -50,7 +50,7 @@ public class Facility { try { - final TypeFactory typeFactory = getTypeFactory( AspectHandler.ROLE ); + final TypeFactory typeFactory = getTypeFactory( AspectHandler.class ); m_aspectHandler = (AspectHandler)typeFactory.create( children[ 0 ].getName() ); } catch( final Exception e ) diff --git a/proposal/myrmidon/src/java/org/apache/antlib/runtime/Import.java b/proposal/myrmidon/src/java/org/apache/antlib/runtime/Import.java index ba9cfba03..0ace7064e 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/runtime/Import.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/runtime/Import.java @@ -14,6 +14,7 @@ import org.apache.myrmidon.api.AbstractTask; import org.apache.myrmidon.api.TaskException; import org.apache.myrmidon.interfaces.deployer.Deployer; import org.apache.myrmidon.interfaces.deployer.DeploymentException; +import org.apache.myrmidon.interfaces.deployer.TypeDeployer; /** * Task to import a tasklib. @@ -45,7 +46,8 @@ public class Import try { final Deployer deployer = (Deployer)getService( Deployer.class ); - deployer.deploy( m_lib ); + TypeDeployer typeDeployer = deployer.createDeployer( m_lib ); + typeDeployer.deployAll(); } catch( final DeploymentException de ) { diff --git a/proposal/myrmidon/src/java/org/apache/antlib/runtime/TypeDef.java b/proposal/myrmidon/src/java/org/apache/antlib/runtime/TypeDef.java index 147d4ebc2..843030d3e 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/runtime/TypeDef.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/runtime/TypeDef.java @@ -24,7 +24,7 @@ public class TypeDef m_type = type; } - protected String getTypeName() + protected String getRoleShorthand() { return m_type; } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java index f69e1a377..dd7caa22c 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java @@ -403,6 +403,9 @@ public class DefaultConfigurer return configurer; } + /** + * Creates and configures an inline object. + */ private Object setupChild( final ConfigurationState state, final Configuration element, final Context context, @@ -424,14 +427,13 @@ public class DefaultConfigurer if( type.isInterface() ) { child = createdTypedObject( name, type ); - configureObject( child, element, context ); } else { child = createObject( type ); - configureObject( child, element, context ); } } + configureObject( child, element, context ); return child; } @@ -444,7 +446,7 @@ public class DefaultConfigurer final Class type ) throws ConfigurationException { - final TypeFactory factory = getTypeFactory( type.getName() ); + final TypeFactory factory = getTypeFactory( type ); try { return factory.create( name ); @@ -481,7 +483,7 @@ public class DefaultConfigurer /** * Locates a type factory. */ - protected final TypeFactory getTypeFactory( final String role ) + protected final TypeFactory getTypeFactory( final Class role ) throws ConfigurationException { try @@ -490,7 +492,7 @@ public class DefaultConfigurer } catch( final TypeException te ) { - final String message = REZ.getString( "no-factory-for-role.error", role ); + final String message = REZ.getString( "no-factory-for-role.error", role.getName() ); throw new ConfigurationException( message, te ); } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties index 28f739b8f..746848141 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties @@ -21,4 +21,5 @@ bad-set-element.error=Could not handle element <{1}>, nested in element <{0}>. no-content.error=Text content is not allowed for element <{0}>. bad-set-content.error=Could not set text content for element <{0}>. typed-adder-non-interface.error=The typed adder for class "{0}" must have a single parameter that is an interface rather than {1} which defines a class. -no-factory-for-role.error=Unable to locate type factory for role "{0}" \ No newline at end of file +no-factory-for-role.error=Unable to locate type factory for role "{0}" +create-typed-object.error=Could not create an object of type "{0}" of class {1}. \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/converter/DefaultMasterConverter.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/converter/DefaultMasterConverter.java index 6c1ef5b51..be6d5876f 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/converter/DefaultMasterConverter.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/converter/DefaultMasterConverter.java @@ -53,7 +53,7 @@ public class DefaultMasterConverter final TypeManager typeManager = (TypeManager)componentManager.lookup( TypeManager.ROLE ); try { - m_factory = typeManager.getFactory( Converter.ROLE ); + m_factory = typeManager.getFactory( Converter.class ); } catch( final TypeException te ) { @@ -132,11 +132,10 @@ public class DefaultMasterConverter final Class destination ) throws ConverterException { - Class clazz = destination; - //TODO: Maybe we should search the source classes hierarchy aswell - final Class terminator = Object.class; - while( terminator != clazz ) + for( Class clazz = destination; + clazz != null; + clazz = clazz.getSuperclass() ) { final String name = m_registry.getConverterName( originalClass.getName(), @@ -145,8 +144,6 @@ public class DefaultMasterConverter { return name; } - - clazz = clazz.getSuperclass(); } final String message = 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 938a2918d..f04216905 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 @@ -14,33 +14,22 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; -import java.util.Enumeration; import java.util.HashMap; +import java.util.Map; import java.util.jar.Manifest; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; import org.apache.avalon.excalibur.extension.Extension; import org.apache.avalon.excalibur.extension.OptionalPackage; import org.apache.avalon.excalibur.extension.PackageManager; 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.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.avalon.framework.configuration.SAXConfigurationHandler; import org.apache.avalon.framework.logger.AbstractLogEnabled; -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.deployer.TypeDeployer; 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.XMLReader; /** * This class deploys a .tsk file into a registry. @@ -49,16 +38,38 @@ import org.xml.sax.XMLReader; */ public class DefaultDeployer extends AbstractLogEnabled - implements Deployer, Initializable, Composable + implements Deployer, Composable { private final static Resources REZ = ResourceManager.getPackageResources( DefaultDeployer.class ); - private ConverterRegistry m_converterRegistry; - private TypeManager m_typeManager; - private RoleManager m_roleManager; + private Deployer m_parent; + private ComponentManager m_componentManager; private PackageManager m_packageManager; + /** Map from ClassLoader to the deployer for that class loader. */ + private Map m_classLoaderDeployers = new HashMap(); + + /** + * Map from File to the ClassLoader for that library. This map is shared + * by all descendents of the root deployer. + */ + private Map m_fileDeployers; + + /** + * Creates a root deployer. + */ + public DefaultDeployer() + { + m_fileDeployers = new HashMap(); + } + + private DefaultDeployer( final DefaultDeployer parent ) + { + m_parent = parent; + m_fileDeployers = parent.m_fileDeployers; + } + /** * Retrieve relevent services needed to deploy. * @@ -68,145 +79,99 @@ public class DefaultDeployer public void compose( final ComponentManager componentManager ) throws ComponentException { - m_converterRegistry = (ConverterRegistry)componentManager.lookup( ConverterRegistry.ROLE ); - m_typeManager = (TypeManager)componentManager.lookup( TypeManager.ROLE ); - m_roleManager = (RoleManager)componentManager.lookup( RoleManager.ROLE ); - + m_componentManager = componentManager; final ExtensionManager extensionManager = (ExtensionManager)componentManager.lookup( ExtensionManager.ROLE ); m_packageManager = new PackageManager( extensionManager ); } - public void initialize() - throws Exception + /** + * Creates a child deployer. + */ + public Deployer createChildDeployer( ComponentManager componentManager ) + throws ComponentException { - final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - final SAXParser saxParser = saxParserFactory.newSAXParser(); - final XMLReader parser = saxParser.getXMLReader(); - //parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false ); - - final SAXConfigurationHandler handler = new SAXConfigurationHandler(); - parser.setContentHandler( handler ); - parser.setErrorHandler( handler ); - - final ClassLoader classLoader = getClass().getClassLoader(); - - final Enumeration enum = classLoader.getResources( Deployment.DESCRIPTOR_NAME ); - while( enum.hasMoreElements() ) - { - final URL url = (URL)enum.nextElement(); - parser.parse( url.toString() ); - - final String message = REZ.getString( "url-deploy.notice", url ); - getLogger().debug( message ); - - deployFromDescriptor( handler.getConfiguration(), classLoader, url ); - } + final DefaultDeployer child = new DefaultDeployer( this ); + setupLogger( child ); + child.compose( componentManager ); + return child; } - public void deploy( final File file ) + /** + * Returns the deployer for a ClassLoader, creating the deployer if + * necessary. + */ + public TypeDeployer createDeployer( final ClassLoader loader ) throws DeploymentException { - if( getLogger().isInfoEnabled() ) - { - final String message = REZ.getString( "file-deploy.notice", file ); - getLogger().info( message ); - } - - checkFile( file ); - 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 ) - { - throw de; + return createDeployment( loader, null ); } - catch( final Exception e ) + catch( Exception e ) { - final String message = REZ.getString( "deploy-lib.error" ); + final String message = REZ.getString( "deploy-from-classloader.error" ); throw new DeploymentException( message, e ); } } - public void deployConverter( final String name, final File file ) + /** + * Returns the deployer for a type library, creating the deployer if + * necessary. + */ + public TypeDeployer createDeployer( final File file ) throws DeploymentException { - checkFile( file ); - - final Deployment deployment = new Deployment( file ); - final Configuration descriptor = deployment.getDescriptor(); - final DefaultTypeFactory factory = new DefaultTypeFactory( deployment.getURL() ); - try { - final Configuration[] converters = - descriptor.getChild( "converters" ).getChildren( "converter" ); - - for( int i = 0; i < converters.length; i++ ) - { - if( converters[ i ].getAttribute( "classname" ).equals( name ) ) - { - handleConverter( converters[ i ], factory ); - break; - } - } - } - catch( final ConfigurationException ce ) - { - final String message = REZ.getString( "bad-descriptor.error" ); - throw new DeploymentException( message, ce ); + URLClassLoader classLoader = getClassLoaderForFile( file ); + return createDeployment( classLoader, file.toURL() ); } - catch( final Exception e ) + catch( Exception e ) { - final String message = REZ.getString( "deploy-converter.error", name ); + final String message = REZ.getString( "deploy-from-file.error", file ); throw new DeploymentException( message, e ); } } - public void deployType( final String role, final String name, final File file ) - throws DeploymentException + /** + * Locates the classloader for a typelib file. + */ + private URLClassLoader getClassLoaderForFile( final File file ) + throws Exception { - checkFile( file ); + File canonFile = file.getCanonicalFile(); - final String shorthand = getNameForRole( role ); - final Deployment deployment = new Deployment( file ); - final Configuration descriptor = deployment.getDescriptor(); - final DefaultTypeFactory factory = new DefaultTypeFactory( deployment.getURL() ); - - try - { - final Configuration[] datatypes = - descriptor.getChild( "types" ).getChildren( shorthand ); - - for( int i = 0; i < datatypes.length; i++ ) - { - if( datatypes[ i ].getAttribute( "name" ).equals( name ) ) - { - handleType( role, datatypes[ i ], factory ); - break; - } - } - } - catch( final ConfigurationException ce ) + // Locate cached classloader, creating it if necessary + URLClassLoader classLoader = (URLClassLoader)m_fileDeployers.get( canonFile ); + if( classLoader == null ) { - final String message = REZ.getString( "bad-descriptor.error" ); - throw new DeploymentException( message, ce ); + checkFile( canonFile ); + final File[] extensions = getOptionalPackagesFor( canonFile ); + final URL[] urls = buildClasspath( canonFile, extensions ); + classLoader = new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() ); + m_fileDeployers.put( canonFile, classLoader ); } - catch( final Exception e ) + return classLoader; + } + + /** + * Creates a deployer for a ClassLoader. + */ + private Deployment createDeployment( final ClassLoader loader, + final URL jarUrl ) throws Exception + { + // Locate cached deployer, creating it if necessary + Deployment deployment = (Deployment)m_classLoaderDeployers.get( loader ); + if( deployment == null ) { - final String message = REZ.getString( "deploy-type.error", name ); - throw new DeploymentException( message, e ); + deployment = new Deployment( loader, m_componentManager ); + setupLogger( deployment ); + deployment.loadDescriptors( jarUrl ); + m_classLoaderDeployers.put( loader, deployment ); } + + return deployment; } private URL[] buildClasspath( final File file, final File[] dependencies ) @@ -243,10 +208,10 @@ public class DefaultDeployer if( getLogger().isDebugEnabled() ) { final String message1 = - REZ.getString( "available-extensions", Arrays.asList( available ) ); + REZ.getString( "available-extensions.notice", Arrays.asList( available ) ); getLogger().debug( message1 ); final String message2 = - REZ.getString( "required-extensions", Arrays.asList( required ) ); + REZ.getString( "required-extensions.notice", Arrays.asList( required ) ); getLogger().debug( message2 ); } @@ -279,7 +244,7 @@ public class DefaultDeployer } final String message = - REZ.getString( "unsatisfied.extensions", new Integer( size ) ); + REZ.getString( "unsatisfied.extensions.error", new Integer( size ) ); throw new Exception( message ); } @@ -288,87 +253,9 @@ public class DefaultDeployer return OptionalPackage.toFiles( packages ); } - private void deployFromDescriptor( final Configuration descriptor, - final ClassLoader classLoader, - final URL url ) - throws DeploymentException, Exception - { - try - { - //Have to keep a new factory per role - //To avoid name clashes (ie a datatype and task with same name) - final HashMap factorys = new HashMap(); - - final Configuration[] types = descriptor.getChild( "types" ).getChildren(); - for( int i = 0; i < types.length; i++ ) - { - final String name = types[ i ].getName(); - final String role = getRoleForName( name ); - final DefaultTypeFactory factory = getFactory( role, classLoader, factorys ); - handleType( role, types[ i ], factory ); - } - - final DefaultTypeFactory factory = new DefaultTypeFactory( classLoader ); - final Configuration[] converters = descriptor.getChild( "converters" ).getChildren(); - for( int i = 0; i < converters.length; i++ ) - { - handleConverter( converters[ i ], factory ); - } - } - catch( final DeploymentException de ) - { - throw de; - } - catch( final Exception e ) - { - final String message = REZ.getString( "deploy-lib.error", url ); - throw new DeploymentException( message, e ); - } - } - - private DefaultTypeFactory getFactory( final String role, - final ClassLoader classLoader, - final HashMap factorys ) - { - DefaultTypeFactory factory = (DefaultTypeFactory)factorys.get( role ); - - if( null == factory ) - { - factory = new DefaultTypeFactory( classLoader ); - factorys.put( role, factory ); - } - - return factory; - } - - private String getNameForRole( final String role ) - throws DeploymentException - { - final String name = m_roleManager.getNameForRole( role ); - - if( null == name ) - { - final String message = REZ.getString( "unknown-name4role.error", role ); - throw new DeploymentException( message ); - } - - return name; - } - - private String getRoleForName( final String name ) - throws DeploymentException - { - final String role = m_roleManager.getRoleForName( name ); - - if( null == role ) - { - final String message = REZ.getString( "unknown-role4name.error", name ); - throw new DeploymentException( message ); - } - - return role; - } - + /** + * Ensures a file exists and is not a directory. + */ private void checkFile( final File file ) throws DeploymentException { @@ -385,43 +272,4 @@ public class DefaultDeployer } } - private void handleConverter( final Configuration converter, - final DefaultTypeFactory factory ) - throws Exception - { - final String name = converter.getAttribute( "classname" ); - final String source = converter.getAttribute( "source" ); - final String destination = converter.getAttribute( "destination" ); - - m_converterRegistry.registerConverter( name, source, destination ); - - factory.addNameClassMapping( name, name ); - m_typeManager.registerType( Converter.ROLE, name, factory ); - - if( getLogger().isDebugEnabled() ) - { - final String message = - REZ.getString( "register-converter.notice", name, source, destination ); - getLogger().debug( message ); - } - } - - private void handleType( final String role, - final Configuration type, - final DefaultTypeFactory factory ) - throws Exception - { - final String name = type.getAttribute( "name" ); - final String className = type.getAttribute( "classname" ); - - factory.addNameClassMapping( name, className ); - m_typeManager.registerType( role, name, factory ); - - if( getLogger().isDebugEnabled() ) - { - final String message = - REZ.getString( "register-role.notice", role, name, className ); - getLogger().debug( message ); - } - } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Deployment.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Deployment.java index 70c6f0d5c..a4c0029b8 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Deployment.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/Deployment.java @@ -7,99 +7,391 @@ */ package org.apache.myrmidon.components.deployer; -import java.io.File; -import java.io.IOException; +import java.io.FileNotFoundException; import java.net.URL; -import javax.xml.parsers.ParserConfigurationException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.avalon.framework.component.ComponentException; +import org.apache.avalon.framework.component.ComponentManager; 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.AbstractLogEnabled; +import org.apache.myrmidon.converter.Converter; +import org.apache.myrmidon.interfaces.converter.ConverterRegistry; import org.apache.myrmidon.interfaces.deployer.DeploymentException; -import org.xml.sax.SAXException; +import org.apache.myrmidon.interfaces.deployer.TypeDeployer; +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.XMLReader; /** - * This class deploys a .tsk file into a registry. + * This class deploys type libraries from a ClassLoader into a registry. * * @author Peter Donald */ -public class Deployment +class Deployment + extends AbstractLogEnabled + implements TypeDeployer { private final static Resources REZ = ResourceManager.getPackageResources( Deployment.class ); - public final static String DESCRIPTOR_NAME = "META-INF/ant-descriptor.xml"; + private final static String DESCRIPTOR_NAME = "META-INF/ant-descriptor.xml"; + private final static String ROLE_DESCRIPTOR = "META-INF/ant-roles.xml"; - private File m_file; + private ClassLoader m_classLoader; + private ConverterRegistry m_converterRegistry; + private TypeManager m_typeManager; + private RoleManager m_roleManager; + private String[] m_descriptorUrls; + private Configuration[] m_descriptors; + private DefaultTypeFactory m_converterFactory; - private Configuration m_descriptor; + /** Map from role name -> DefaultTypeFactory for that role. */ + private Map m_factories = new HashMap(); - public Deployment( final File file ) + public Deployment( final ClassLoader classLoader, ComponentManager manager ) + throws ComponentException { - m_file = file; + // Locate the various components needed + m_classLoader = classLoader; + m_converterRegistry = (ConverterRegistry)manager.lookup( ConverterRegistry.ROLE ); + m_typeManager = (TypeManager)manager.lookup( TypeManager.ROLE ); + m_roleManager = (RoleManager)manager.lookup( RoleManager.ROLE ); } - public Configuration getDescriptor() + /** + * Load the descriptors. Deploys all roles, then loads the descriptors + * for, but does not deploy, all the types. + */ + public void loadDescriptors( URL jarUrl ) + throws Exception + { + final ArrayList descriptors = new ArrayList(); + + // Create a SAX parser to assemble the descriptors into Configuration + // objects + final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); + final SAXParser saxParser = saxParserFactory.newSAXParser(); + final XMLReader parser = saxParser.getXMLReader(); + //parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false ); + + final SAXConfigurationHandler handler = new SAXConfigurationHandler(); + parser.setContentHandler( handler ); + parser.setErrorHandler( handler ); + + // Load the role descriptors, and deploy all roles + final List roleUrls = locateResources( ROLE_DESCRIPTOR, jarUrl ); + for( Iterator iterator = roleUrls.iterator(); iterator.hasNext(); ) + { + String url = (String)iterator.next(); + try + { + parser.parse( url ); + } + catch( FileNotFoundException e ) + { + // Ignore - this happens when jarUrl != null and the Jar does + // not contain a role descriptor. + continue; + } + + handleRoleDescriptor( handler.getConfiguration(), url ); + } + + // Load type descriptors + final List typeUrls = locateResources( DESCRIPTOR_NAME, jarUrl ); + for( Iterator iterator = typeUrls.iterator(); iterator.hasNext(); ) + { + String url = (String)iterator.next(); + try + { + parser.parse( url.toString() ); + } + catch( FileNotFoundException e ) + { + // Ignore - this happens when jarUrl != null and the Jar does + // not contain a type descriptor + } + + descriptors.add( handler.getConfiguration() ); + } + m_descriptorUrls = (String[])typeUrls.toArray( new String[ typeUrls.size() ] ); + m_descriptors = (Configuration[])descriptors.toArray( new Configuration[ descriptors.size() ] ); + } + + /** + * Deploys everything in the type library. + */ + public void deployAll() throws DeploymentException { - if( null == m_descriptor ) + for( int i = 0; i < m_descriptors.length; i++ ) { - m_descriptor = buildDescriptor(); + Configuration descriptor = m_descriptors[ i ]; + deployFromDescriptor( descriptor, m_classLoader, m_descriptorUrls[i] ); } + } - return m_descriptor; + /** + * Deploys a single type in the type library. + */ + public void deployType( final String roleShorthand, final String typeName ) + throws DeploymentException + { + try + { + // Locate the entry for the type + for( int i = 0; i < m_descriptors.length; i++ ) + { + Configuration descriptor = m_descriptors[ i ]; + final Configuration[] datatypes = + descriptor.getChild( "types" ).getChildren( roleShorthand ); + for( int j = 0; j < datatypes.length; j++ ) + { + Configuration datatype = datatypes[ j ]; + if( datatype.getAttribute( "name" ).equals( typeName ) ) + { + final String className = datatype.getAttribute( "classname" ); + handleType( roleShorthand, typeName, className ); + } + } + } + } + catch( Exception e ) + { + final String message = REZ.getString( "deploy-type.error", roleShorthand, typeName ); + throw new DeploymentException( message, e ); + } } - public URL getURL() + /** + * Deploys a single type from the type library. + */ + public void deployType( String roleShorthand, String typeName, String className ) throws DeploymentException { try { - return m_file.getCanonicalFile().toURL(); + handleType( roleShorthand, typeName, className ); } - catch( final IOException ioe ) + catch( Exception e ) { - final String message = REZ.getString( "bad-url.error", m_file ); - throw new DeploymentException( message, ioe ); + final String message = REZ.getString( "deploy-type.error", roleShorthand, typeName ); + throw new DeploymentException( message, e ); } } - private Configuration buildDescriptor() + /** + * Deploys a converter from the type library. The converter definition + * is read from the type library descriptor. + */ + public void deployConverter( String className ) throws DeploymentException { - final String systemID = "jar:" + getURL() + "!/" + DESCRIPTOR_NAME; + // TODO - implement this + throw new DeploymentException( "Not implemented." ); + } + /** + * Deploys a converter from the type library. + */ + public void deployConverter( String className, String srcClass, String destClass ) + throws DeploymentException + { try { - final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - final SAXParser saxParser = saxParserFactory.newSAXParser(); - final XMLReader parser = saxParser.getXMLReader(); - //parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false ); + handleConverter( className, srcClass, destClass ); + } + catch( Exception e ) + { + final String message = REZ.getString( "deploy-converter.error", srcClass, destClass ); + throw new DeploymentException( message, e ); + } + } - final SAXConfigurationHandler handler = new SAXConfigurationHandler(); - parser.setContentHandler( handler ); - parser.setErrorHandler( handler ); + /** + * Locates all resources of a particular name. + */ + private List locateResources( final String resource, final URL jarUrl ) + throws Exception + { + ArrayList urls = new ArrayList(); + if( jarUrl != null ) + { + final String systemID = "jar:" + jarUrl + "!/" + resource; + urls.add( systemID ); + } + else + { + Enumeration enum = m_classLoader.getResources( resource ); + while( enum.hasMoreElements() ) + { + urls.add( enum.nextElement().toString() ); + } + } - parser.parse( systemID ); - return handler.getConfiguration(); + return urls; + } + + /** + * Configure RoleManager based on contents of single descriptor. + * + * @param descriptor the descriptor + * @exception ConfigurationException if an error occurs + */ + private void handleRoleDescriptor( final Configuration descriptor, + final String url ) + throws ConfigurationException + { + final String message = REZ.getString( "url-deploy-roles.notice", url ); + getLogger().info( message ); + + final Configuration[] types = descriptor.getChildren( "role" ); + for( int i = 0; i < types.length; i++ ) + { + final String name = types[ i ].getAttribute( "shorthand" ); + final String role = types[ i ].getAttribute( "name" ); + m_roleManager.addNameRoleMapping( name, role ); + + if( getLogger().isDebugEnabled() ) + { + final String debugMessage = REZ.getString( "register-role.notice", role, name ); + getLogger().debug( debugMessage ); + } } - catch( final SAXException se ) + } + + /** + * Deploys all types from a typelib descriptor. + */ + private void deployFromDescriptor( final Configuration descriptor, + final ClassLoader classLoader, + final String url ) + throws DeploymentException + { + try { - final String message = REZ.getString( "bad-descriptor.error" ); - throw new DeploymentException( message, se ); + final String message = REZ.getString( "url-deploy-types.notice", url ); + getLogger().info( message ); + + // Deploy all the types + final Configuration[] typeEntries = descriptor.getChild( "types" ).getChildren(); + for( int i = 0; i < typeEntries.length; i++ ) + { + final Configuration typeEntry = typeEntries[ i ]; + final String roleShorthand = typeEntry.getName(); + final String typeName = typeEntry.getAttribute( "name" ); + final String className = typeEntry.getAttribute( "classname" ); + handleType( roleShorthand, typeName, className ); + } + + // Deploy all the converters + final Configuration[] converterEntries = descriptor.getChild( "converters" ).getChildren(); + for( int i = 0; i < converterEntries.length; i++ ) + { + final Configuration converter = converterEntries[ i ]; + final String className = converter.getAttribute( "classname" ); + final String source = converter.getAttribute( "source" ); + final String destination = converter.getAttribute( "destination" ); + handleConverter( className, source, destination ); + } } - catch( final ParserConfigurationException pce ) + catch( final Exception e ) { - final String message = REZ.getString( "bad-parser.error" ); - throw new DeploymentException( message, pce ); + final String message = REZ.getString( "deploy-lib.error", url ); + throw new DeploymentException( message, e ); } - catch( final IOException ioe ) + } + + /** + * Returns the type factory for a role. + */ + private DefaultTypeFactory getFactory( final Class roleType) + { + DefaultTypeFactory factory = (DefaultTypeFactory)m_factories.get( roleType ); + + if( null == factory ) { - final String message = REZ.getString( "bad-read.error" ); - throw new DeploymentException( message, ioe ); + factory = new DefaultTypeFactory( m_classLoader ); + m_factories.put( roleType, factory ); } + + return factory; } + + /** + * Handles a converter definition. + */ + private void handleConverter( final String className, + final String source, + final String destination ) throws Exception + { + m_converterRegistry.registerConverter( className, source, destination ); + + if( m_converterFactory == null ) + { + m_converterFactory = new DefaultTypeFactory( m_classLoader ); + } + m_converterFactory.addNameClassMapping( className, className ); + m_typeManager.registerType( Converter.class, className, m_converterFactory ); + + if( getLogger().isDebugEnabled() ) + { + final String message = + REZ.getString( "register-converter.notice", source, destination ); + getLogger().debug( message ); + } + } + + /** + * Handles a type definition. + */ + private void handleType( final String roleShorthand, + final String typeName, + final String className ) + throws Exception + { + // TODO - detect duplicates + final String role = getRoleForName( roleShorthand ); + final Class roleType = m_classLoader.loadClass( role ); + final DefaultTypeFactory factory = getFactory( roleType ); + factory.addNameClassMapping( typeName, className ); + m_typeManager.registerType( roleType, typeName, factory ); + + if( getLogger().isDebugEnabled() ) + { + final String message = + REZ.getString( "register-type.notice", roleShorthand, typeName ); + getLogger().debug( message ); + } + } + + /** + * Determines the role name from shorthand name. + */ + private String getRoleForName( final String name ) + throws DeploymentException + { + final String role = m_roleManager.getRoleForName( name ); + + if( null == role ) + { + final String message = REZ.getString( "unknown-role4name.error", name ); + throw new DeploymentException( message ); + } + + return role; + } + } 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 3138fa3bc..a6908d198 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 @@ -1,24 +1,18 @@ -register-converter.notice=Registered converter {0} that converts from {1} to {2}. -register-role.notice=Registered {0}/{1} as {2}. -url-deploy.notice=Deploying {0}. -file-deploy.notice=Deploying AntLib file ({0}). +register-converter.notice=Registered converter that converts from {1} to {2}. +register-type.notice=Registered type {0}/{1}. +register-role.notice=Registered role {0} with shorthand name {1}. +url-deploy-types.notice=Registering types from "{0}". +url-deploy-roles.notice=Registering roles from "{0}". -deploy-lib.error=Error deploying library from {0}. -deploy-converter.error=Failed to deploy {0} converter. -bad-descriptor.error=Malformed descriptor. -deploy-type.error=Failed to deploy {0} type. -unknown-name4role.error=RoleManager does not know name for role {0}. -unknown-role4name.error=RoleManager does not know role for name {0}. -no-file.error=Could not find application archive at {0}. -file-is-dir.error=Could not find application archive at {0} as it is a directory. +deploy-from-classloader.error=Could not register types from ClassLoader {0}. +deploy-from-file.error=Could not register types from type library "{0}". +deploy-lib.error=Could not register types from "{0}". +deploy-converter.error=Could not register converter that converts from {0} to {1}. +deploy-type.error=Could not register type {0}/{1}. +unknown-role4name.error=Unknown role "{0}". +no-file.error=Could not find type library "{0}". +file-is-dir.error=Type library "{0}" 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 +available-extensions.notice=The list of available extensions for type library includes; {0} +required-extensions.notice=The list of required extensions for type library includes; {0} +unsatisfied.extensions.error=Missing {0} extensions for type library. diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java index 2e9fcdfa0..a71d7afc3 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java @@ -27,6 +27,7 @@ import org.apache.myrmidon.interfaces.converter.ConverterRegistry; import org.apache.myrmidon.interfaces.converter.MasterConverter; import org.apache.myrmidon.interfaces.deployer.Deployer; import org.apache.myrmidon.interfaces.deployer.DeploymentException; +import org.apache.myrmidon.interfaces.deployer.TypeDeployer; import org.apache.myrmidon.interfaces.embeddor.Embeddor; import org.apache.myrmidon.interfaces.executor.Executor; import org.apache.myrmidon.interfaces.extensions.ExtensionManager; @@ -106,7 +107,7 @@ public class DefaultEmbeddor throws Exception { - final TypeFactory factory = m_typeManager.getFactory( ProjectBuilder.ROLE ); + final TypeFactory factory = m_typeManager.getFactory( ProjectBuilder.class ); final ProjectBuilder builder = (ProjectBuilder)factory.create( type ); setupLogger( builder ); @@ -181,6 +182,12 @@ public class DefaultEmbeddor public void start() throws Exception { + // Deploy all type libraries found in the classpath + final ClassLoader libClassloader = Thread.currentThread().getContextClassLoader(); + final TypeDeployer typeDeployer = m_deployer.createDeployer( libClassloader ); + typeDeployer.deployAll(); + + // Deploy all type libraries in the lib directory final ExtensionFileFilter filter = new ExtensionFileFilter( ".atl" ); deployFromDirectory( m_deployer, m_taskLibDir, filter ); } @@ -479,6 +486,9 @@ public class DefaultEmbeddor } } + /** + * Deploys all type libraries in a directory. + */ private void deployFromDirectory( final Deployer deployer, final File directory, final FilenameFilter filter ) @@ -492,6 +502,9 @@ public class DefaultEmbeddor } } + /** + * Deploys a set of type libraries. + */ private void deployFiles( final Deployer deployer, final File[] files ) throws DeploymentException { @@ -508,7 +521,8 @@ public class DefaultEmbeddor try { final File file = files[ i ].getCanonicalFile(); - deployer.deploy( file ); + final TypeDeployer typeDeployer = deployer.createDeployer( file ); + typeDeployer.deployAll(); } catch( final DeploymentException de ) { diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/executor/DefaultExecutor.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/executor/DefaultExecutor.java index 0d0e2a6a6..ad31d2568 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/executor/DefaultExecutor.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/executor/DefaultExecutor.java @@ -32,8 +32,6 @@ public class DefaultExecutor private final static Resources REZ = ResourceManager.getPackageResources( DefaultExecutor.class ); - private final static String TASK_ROLE = Task.class.getName(); - private Configurer m_configurer; /** @@ -81,7 +79,7 @@ public class DefaultExecutor { try { - final TypeFactory factory = frame.getTypeManager().getFactory( TASK_ROLE ); + final TypeFactory factory = frame.getTypeManager().getFactory( Task.class ); return (Task)factory.create( name ); } catch( final TypeException te ) diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/role/DefaultRoleManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/role/DefaultRoleManager.java index f6b46326f..f78ad8221 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/role/DefaultRoleManager.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/role/DefaultRoleManager.java @@ -7,19 +7,10 @@ */ package org.apache.myrmidon.components.role; -import java.net.URL; -import java.util.Enumeration; import java.util.HashMap; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; 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.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.avalon.framework.configuration.SAXConfigurationHandler; import org.apache.myrmidon.interfaces.role.RoleManager; -import org.xml.sax.XMLReader; /** * Interface to manage roles and mapping to names. @@ -28,13 +19,11 @@ import org.xml.sax.XMLReader; * @version CVS $Revision$ $Date$ */ public class DefaultRoleManager - implements RoleManager, Initializable + implements RoleManager { private final static Resources REZ = ResourceManager.getPackageResources( DefaultRoleManager.class ); - private final static String ROLE_DESCRIPTOR = "META-INF/ant-roles.xml"; - /** Parent RoleManager for nested resolution */ private final RoleManager m_parent; @@ -63,51 +52,6 @@ public class DefaultRoleManager m_parent = parent; } - /** - * initialize the RoleManager. - * This involves reading all Role descriptors in common classloader. - * - * @exception Exception if an error occurs - */ - public void initialize() - throws Exception - { - final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - final SAXParser saxParser = saxParserFactory.newSAXParser(); - final XMLReader parser = saxParser.getXMLReader(); - //parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false ); - - final SAXConfigurationHandler handler = new SAXConfigurationHandler(); - parser.setContentHandler( handler ); - parser.setErrorHandler( handler ); - - final Enumeration enum = getClass().getClassLoader().getResources( ROLE_DESCRIPTOR ); - while( enum.hasMoreElements() ) - { - final URL url = (URL)enum.nextElement(); - parser.parse( url.toString() ); - handleDescriptor( handler.getConfiguration() ); - } - } - - /** - * Configure RoleManager based on contents of single descriptor. - * - * @param descriptor the descriptor - * @exception ConfigurationException if an error occurs - */ - private void handleDescriptor( final Configuration descriptor ) - throws ConfigurationException - { - final Configuration[] types = descriptor.getChildren( "role" ); - for( int i = 0; i < types.length; i++ ) - { - final String name = types[ i ].getAttribute( "shorthand" ); - final String role = types[ i ].getAttribute( "name" ); - addNameRoleMapping( name, role ); - } - } - /** * Find Role name based on shorthand name. * @@ -155,14 +99,14 @@ public class DefaultRoleManager throws IllegalArgumentException { final String oldRole = (String)m_names.get( name ); - if( null != oldRole && oldRole.equals( role ) ) + if( null != oldRole && ! oldRole.equals( role ) ) { final String message = REZ.getString( "duplicate-name.error", oldRole ); throw new IllegalArgumentException( message ); } final String oldName = (String)m_roles.get( role ); - if( null != oldName && oldName.equals( name ) ) + if( null != oldName && ! oldName.equals( name ) ) { final String message = REZ.getString( "duplicate-role.error", oldName ); throw new IllegalArgumentException( message ); diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/type/DefaultTypeManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/type/DefaultTypeManager.java index 94021dc74..2a674f48f 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/type/DefaultTypeManager.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/type/DefaultTypeManager.java @@ -28,7 +28,7 @@ public class DefaultTypeManager ///Parent type manager to inherit values from. private final DefaultTypeManager m_parent; - ///Maps role to MultiSourceTypeFactory. + ///Maps role Class to MultiSourceTypeFactory. private final HashMap m_roleMap = new HashMap(); public DefaultTypeManager() @@ -41,7 +41,7 @@ public class DefaultTypeManager m_parent = parent; } - public void registerType( final String role, + public void registerType( final Class role, final String shorthandName, final TypeFactory factory ) throws TypeException @@ -50,7 +50,7 @@ public class DefaultTypeManager msFactory.register( shorthandName, factory ); } - public TypeFactory getFactory( final String role ) + public TypeFactory getFactory( final Class role ) throws TypeException { return createFactory( role ); @@ -61,7 +61,7 @@ public class DefaultTypeManager return new DefaultTypeManager( this ); } - protected final MultiSourceTypeFactory lookupFactory( final String role ) + protected final MultiSourceTypeFactory lookupFactory( final Class role ) { return (MultiSourceTypeFactory)m_roleMap.get( role ); } @@ -74,7 +74,7 @@ public class DefaultTypeManager * @return the Factory for interface * @exception TypeException role does not specify accessible work interface */ - private MultiSourceTypeFactory createFactory( final String role ) + private MultiSourceTypeFactory createFactory( final Class role ) throws TypeException { MultiSourceTypeFactory factory = (MultiSourceTypeFactory)m_roleMap.get( role ); @@ -92,17 +92,7 @@ public class DefaultTypeManager ///If we haven't got factory try to create a new one if( null == factory ) { - try - { - //TODO: Should we use ContextClassLoader here ??? Or perhaps try that on failure?? - final Class clazz = Class.forName( role ); - factory = new MultiSourceTypeFactory( clazz ); - } - catch( final Exception e ) - { - final String message = REZ.getString( "no-work-interface.error", role ); - throw new TypeException( message ); - } + factory = new MultiSourceTypeFactory( role ); } m_roleMap.put( role, factory ); @@ -110,7 +100,7 @@ public class DefaultTypeManager return factory; } - private MultiSourceTypeFactory getParentTypedFactory( final String role ) + private MultiSourceTypeFactory getParentTypedFactory( final Class role ) { if( null != m_parent ) { diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java index 36e9b5a54..a6e2f8d6a 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java @@ -28,11 +28,11 @@ import org.apache.avalon.framework.parameters.Parameters; import org.apache.log.Hierarchy; import org.apache.myrmidon.api.TaskContext; import org.apache.myrmidon.api.TaskException; -import org.apache.myrmidon.components.deployer.DefaultDeployer; import org.apache.myrmidon.components.executor.DefaultExecutionFrame; import org.apache.myrmidon.framework.Condition; import org.apache.myrmidon.interfaces.deployer.Deployer; import org.apache.myrmidon.interfaces.deployer.DeploymentException; +import org.apache.myrmidon.interfaces.deployer.TypeDeployer; import org.apache.myrmidon.interfaces.executor.ExecutionFrame; import org.apache.myrmidon.interfaces.executor.Executor; import org.apache.myrmidon.interfaces.model.Project; @@ -61,6 +61,7 @@ public class DefaultWorkspace private TaskContext m_baseContext; private HashMap m_entrys = new HashMap(); private TypeManager m_typeManager; + private Deployer m_deployer; private Hierarchy m_hierarchy; private int m_projectID; @@ -96,6 +97,7 @@ public class DefaultWorkspace m_componentManager = componentManager; m_typeManager = (TypeManager)componentManager.lookup( TypeManager.ROLE ); m_executor = (Executor)componentManager.lookup( Executor.ROLE ); + m_deployer = (Deployer)componentManager.lookup( Deployer.ROLE ); } public void parameterize( final Parameters parameters ) @@ -198,13 +200,16 @@ public class DefaultWorkspace try { + final TypeDeployer typeDeployer = deployer.createDeployer( file ); if( null == typeLib.getRole() ) { - deployer.deploy( file ); + // Deploy everything in the typelib + typeDeployer.deployAll(); } else { - deployer.deployType( typeLib.getRole(), typeLib.getName(), file ); + // Deploy the specified type + typeDeployer.deployType( typeLib.getRole(), typeLib.getName() ); } } catch( final DeploymentException de ) @@ -227,27 +232,34 @@ public class DefaultWorkspace final TypeManager typeManager = m_typeManager.createChildTypeManager(); componentManager.put( TypeManager.ROLE, typeManager ); + //try + //{ + // //Add VFS manager + // // TODO - need to drive this from a typelib descriptor, plus + // // should be adding services to the root frame, rather than here + // final DefaultFileSystemManager vfsManager = new DefaultFileSystemManager(); + // vfsManager.setBaseFile( project.getBaseDirectory() ); + // componentManager.put( FileSystemManager.ROLE, vfsManager ); + //} + //catch( Exception e ) + //{ + // throw new TaskException( e.getMessage(), e ); + //} + //We need to create a new deployer so that it deploys //to project specific TypeManager - final DefaultDeployer deployer = new DefaultDeployer(); - deployer.enableLogging( getLogger() ); - + final Deployer deployer; try { - deployer.compose( componentManager ); + deployer = m_deployer.createChildDeployer( componentManager ); + componentManager.put( Deployer.ROLE, deployer ); } - catch( final ComponentException ce ) + catch( ComponentException e ) { - final String message = REZ.getString( "bad-deployer-config.error" ); - throw new TaskException( message, ce ); + throw new TaskException( e.getMessage(), e ); } - //HACK: Didn't call initialize because Deployer contained in Embeddor - // Already initialized and this would be reduendent - //deployer.initialize(); - - componentManager.put( Deployer.ROLE, deployer ); - + // Deploy the imported typelibs deployTypeLib( deployer, project ); //We need to place projects and ProjectManager diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/AbstractContainerTask.java b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/AbstractContainerTask.java index 3932af4c2..02528c18c 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/AbstractContainerTask.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/AbstractContainerTask.java @@ -109,17 +109,17 @@ public abstract class AbstractContainerTask /** * Locates a type factory. */ - protected final TypeFactory getTypeFactory( final String role ) + protected final TypeFactory getTypeFactory( final Class roleType ) throws TaskException { final TypeManager typeManager = (TypeManager)getService( TypeManager.class ); try { - return typeManager.getFactory( role ); + return typeManager.getFactory( roleType ); } catch( final TypeException te ) { - final String message = REZ.getString( "container.no-factory.error", role ); + final String message = REZ.getString( "container.no-factory.error", roleType.getName() ); throw new TaskException( message, te ); } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/AbstractTypeDef.java b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/AbstractTypeDef.java index 01132fcc2..13409beea 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/AbstractTypeDef.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/AbstractTypeDef.java @@ -8,16 +8,13 @@ package org.apache.myrmidon.framework; import java.io.File; -import java.net.URL; -import java.net.URLClassLoader; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.myrmidon.api.AbstractTask; import org.apache.myrmidon.api.TaskException; -import org.apache.myrmidon.interfaces.role.RoleManager; -import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; -import org.apache.myrmidon.interfaces.type.TypeException; -import org.apache.myrmidon.interfaces.type.TypeManager; +import org.apache.myrmidon.interfaces.deployer.Deployer; +import org.apache.myrmidon.interfaces.deployer.DeploymentException; +import org.apache.myrmidon.interfaces.deployer.TypeDeployer; /** * Abstract task to extend to define a type. @@ -66,44 +63,20 @@ public abstract class AbstractTypeDef throw new TaskException( message ); } - final String typeName = getTypeName(); - final RoleManager roleManager = (RoleManager)getService( RoleManager.class ); - final String role = roleManager.getRoleForName( typeName ); + final String shorthand = getRoleShorthand(); - final ClassLoader classLoader = createClassLoader(); - final DefaultTypeFactory factory = new DefaultTypeFactory( classLoader ); - factory.addNameClassMapping( m_name, m_className ); - - final TypeManager typeManager = (TypeManager)getService( TypeManager.class ); try { - typeManager.registerType( role, m_name, factory ); - } - catch( final TypeException te ) - { - final String message = REZ.getString( "typedef.no-register.error" ); - throw new TaskException( message, te ); - } - } - - protected ClassLoader createClassLoader() - throws TaskException - { - //TODO: Make this support classpath sub-element in future - try - { - final URL url = m_lib.toURL(); - final ClassLoader classLoader = - Thread.currentThread().getContextClassLoader(); - - return new URLClassLoader( new URL[]{url}, classLoader ); + // Locate the deployer, and use it to deploy the type + final Deployer deployer = (Deployer)getService( Deployer.class ); + final TypeDeployer typeDeployer = deployer.createDeployer( m_lib ); + typeDeployer.deployType( shorthand, m_name, m_className ); } - catch( final Exception e ) + catch( DeploymentException e ) { - final String message = REZ.getString( "typedef.bad-classloader.error", e ); - throw new TaskException( message, e ); + throw new TaskException( e.getMessage(), e ); } } - protected abstract String getTypeName(); + protected abstract String getRoleShorthand(); } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/TypeInstanceTask.java b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/TypeInstanceTask.java index 8853b565d..d55a30a39 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/TypeInstanceTask.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/TypeInstanceTask.java @@ -63,7 +63,7 @@ public class TypeInstanceTask try { - final TypeFactory typeFactory = getTypeFactory( DataType.ROLE ); + final TypeFactory typeFactory = getTypeFactory( DataType.class ); m_value = typeFactory.create( configuration.getName() ); } catch( final Exception e ) diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/deployer/Deployer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/deployer/Deployer.java index cddb07df7..be276bf4f 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/deployer/Deployer.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/deployer/Deployer.java @@ -9,9 +9,11 @@ package org.apache.myrmidon.interfaces.deployer; import java.io.File; import org.apache.avalon.framework.component.Component; +import org.apache.avalon.framework.component.ComponentException; +import org.apache.avalon.framework.component.ComponentManager; /** - * This class deploys a .tsk file into a registry. + * This class deploys type libraries into a registry. * * @author Peter Donald */ @@ -21,17 +23,28 @@ public interface Deployer String ROLE = "org.apache.myrmidon.interfaces.deployer.Deployer"; /** - * Deploy a library. + * Returns the deployer for the type libraries contained in a ClassLoader, + * creating the deployer if necessary. * - * @param file the file deployment - * @exception DeploymentException if an error occurs + * @param loader The ClassLoader to get the deployer for. + * @exception DeploymentException if an error occurs. */ - void deploy( File file ) + TypeDeployer createDeployer( ClassLoader loader ) throws DeploymentException; - void deployConverter( String name, File file ) + /** + * Returns the deployer for a type library, creating the deployer if + * necessary. + * + * @param file the file containing the type library. + * @exception DeploymentException if an error occurs. + */ + TypeDeployer createDeployer( File file ) throws DeploymentException; - void deployType( String role, String name, File file ) - throws DeploymentException; + /** + * Creates a child deployer. + */ + Deployer createChildDeployer( ComponentManager componentManager ) + throws ComponentException; } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/deployer/TypeDeployer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/deployer/TypeDeployer.java new file mode 100644 index 000000000..f453987d9 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/deployer/TypeDeployer.java @@ -0,0 +1,54 @@ +/* + * 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.txt file. + */ +package org.apache.myrmidon.interfaces.deployer; + +/** + * A deployer for a type library. Allows individual elements from a type + * library to be deployed. + * + * @author Adam Murdoch + */ +public interface TypeDeployer +{ + /** + * Deploys everything in the type library. + */ + void deployAll() + throws DeploymentException; + + /** + * Deploys a single type from the type library. The type definition is + * read from the type library descriptor. + * + * @param roleShorthand + * The shorthand for the role. + * @param typeName + * The type name. + */ + void deployType( String roleShorthand, String typeName ) + throws DeploymentException; + + /** + * Deploys a single type from the type library. + */ + void deployType( String roleShorthand, String typeName, String className ) + throws DeploymentException; + + /** + * Deploys a converter from the type library. The converter definition + * is read from the type library descriptor. + */ + void deployConverter( String className ) + throws DeploymentException; + + /** + * Deploys a converter from the type library. + */ + void deployConverter( String className, String srcClass, String destClass ) + throws DeploymentException; +} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/role/RoleManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/role/RoleManager.java index aa90c17ad..8dce64ecd 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/role/RoleManager.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/role/RoleManager.java @@ -38,4 +38,13 @@ public interface RoleManager * @return the name */ String getNameForRole( String role ); + + /** + * Adds a role mapping. + * + * @param name the shorthand name. + * @param role the role name. + */ + void addNameRoleMapping( String name, String role ) + throws IllegalArgumentException; } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/type/DefaultTypeFactory.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/type/DefaultTypeFactory.java index 7fcd52490..1b2c0a102 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/type/DefaultTypeFactory.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/type/DefaultTypeFactory.java @@ -7,8 +7,6 @@ */ package org.apache.myrmidon.interfaces.type; -import java.net.URL; -import java.net.URLClassLoader; import java.util.HashMap; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; @@ -28,34 +26,11 @@ public class DefaultTypeFactory ///A Map of shortnames to classnames private final HashMap m_classNames = new HashMap(); - ///A list of URLs from which classLoader is constructed - private final URL[] m_urls; - - ///The parent classLoader (if any) - private final ClassLoader m_parent; - ///The parent classLoader (if any) private ClassLoader m_classLoader; - public DefaultTypeFactory( final URL url ) - { - this( new URL[]{url} ); - } - - public DefaultTypeFactory( final URL[] urls ) - { - this( urls, Thread.currentThread().getContextClassLoader() ); - } - - public DefaultTypeFactory( final URL[] urls, final ClassLoader parent ) - { - m_urls = urls; - m_parent = parent; - } - public DefaultTypeFactory( final ClassLoader classLoader ) { - this( null, null ); m_classLoader = classLoader; } @@ -78,7 +53,7 @@ public class DefaultTypeFactory try { - return getClassLoader().loadClass( className ).newInstance(); + return m_classLoader.loadClass( className ).newInstance(); } catch( final Exception e ) { @@ -100,14 +75,4 @@ public class DefaultTypeFactory return className; } - - private ClassLoader getClassLoader() - { - if( null == m_classLoader ) - { - m_classLoader = new URLClassLoader( m_urls, m_parent ); - } - - return m_classLoader; - } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/type/TypeManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/type/TypeManager.java index ccd427f19..3e0643bb0 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/type/TypeManager.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/type/TypeManager.java @@ -19,11 +19,32 @@ public interface TypeManager { String ROLE = "org.apache.myrmidon.interfaces.type.TypeManager"; - void registerType( String role, String shorthandName, TypeFactory factory ) + /** + * Registers a new type. + * + * @param roleType + * The role interface for the type. Objects created by the factory + * must implement this interface. + * + * @param shorthandName + * The shorthand name for the type. + * + * @param factory + * The type factory. + */ + void registerType( Class roleType, String shorthandName, TypeFactory factory ) throws TypeException; - TypeFactory getFactory( String role ) + /** + * Returns the factory for a role. + */ + TypeFactory getFactory( Class roleType ) throws TypeException; + /** + * Creates a child type manager. The child inherits the type factories + * from this type manager. Additional type factories may be added to the + * child, without affecting this type manager. + */ TypeManager createChildTypeManager(); } diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java index 98122db39..5006b45d0 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java @@ -433,8 +433,8 @@ public class DefaultConfigurerTest final DefaultTypeFactory factory = new DefaultTypeFactory( loader ); factory.addNameClassMapping( "my-type1", MyType1.class.getName() ); factory.addNameClassMapping( "my-type2", MyType2.class.getName() ); - m_typeManager.registerType( MyRole1.class.getName(), "my-type1", factory ); - m_typeManager.registerType( MyRole1.class.getName(), "my-type2", factory ); + m_typeManager.registerType( MyRole1.class, "my-type1", factory ); + m_typeManager.registerType( MyRole1.class, "my-type2", factory ); final ConfigTest6 test = new ConfigTest6(); diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java index 98122db39..5006b45d0 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java @@ -433,8 +433,8 @@ public class DefaultConfigurerTest final DefaultTypeFactory factory = new DefaultTypeFactory( loader ); factory.addNameClassMapping( "my-type1", MyType1.class.getName() ); factory.addNameClassMapping( "my-type2", MyType2.class.getName() ); - m_typeManager.registerType( MyRole1.class.getName(), "my-type1", factory ); - m_typeManager.registerType( MyRole1.class.getName(), "my-type2", factory ); + m_typeManager.registerType( MyRole1.class, "my-type1", factory ); + m_typeManager.registerType( MyRole1.class, "my-type2", factory ); final ConfigTest6 test = new ConfigTest6();