Note this wont run until we break out container-api.jar and place in lib/ so that the runtime/ant1compat classes will work at runtime. At the moment they will compile ma no run. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272374 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -14,7 +14,7 @@ | |||||
| <path id="project.class.path"> | <path id="project.class.path"> | ||||
| <pathelement location="build/classes"/> | <pathelement location="build/classes"/> | ||||
| <fileset dir="lib"> | <fileset dir="lib"> | ||||
| <include name="*.jar"/> | |||||
| <include name="**/*.jar"/> | |||||
| </fileset> | </fileset> | ||||
| </path> | </path> | ||||
| @@ -251,9 +251,7 @@ Legal: | |||||
| <src path="${build.src}" /> | <src path="${build.src}" /> | ||||
| --> | --> | ||||
| <patternset refid="myrmidon-launcher.include"/> | |||||
| <patternset refid="myrmidon-framework.include"/> | <patternset refid="myrmidon-framework.include"/> | ||||
| <patternset refid="myrmidon-container.include"/> | |||||
| <patternset refid="ant1.todo.include"/> | <patternset refid="ant1.todo.include"/> | ||||
| <patternset refid="selftest.include"/> | <patternset refid="selftest.include"/> | ||||
| <patternset refid="selftest-extension1.include"/> | <patternset refid="selftest-extension1.include"/> | ||||
| @@ -269,22 +267,12 @@ Legal: | |||||
| </target> | </target> | ||||
| <target name="setup-patterns" depends="check_for_optional_packages"> | <target name="setup-patterns" depends="check_for_optional_packages"> | ||||
| <patternset id="myrmidon-launcher.include"> | |||||
| <include name="org/apache/myrmidon/launcher/**" /> | |||||
| </patternset> | |||||
| <patternset id="myrmidon-framework.include"> | <patternset id="myrmidon-framework.include"> | ||||
| <include name="org/apache/myrmidon/interfaces/**" /> | <include name="org/apache/myrmidon/interfaces/**" /> | ||||
| <include name="org/apache/myrmidon/framework/**" /> | <include name="org/apache/myrmidon/framework/**" /> | ||||
| </patternset> | </patternset> | ||||
| <patternset id="myrmidon-container.include"> | |||||
| <include name="org/apache/myrmidon/components/**" /> | |||||
| <include name="org/apache/myrmidon/frontends/**" /> | |||||
| <include name="org/apache/myrmidon/*" /> | |||||
| <exclude name="**/TransformingProjectBuilder.java" unless="trax.present"/> | |||||
| </patternset> | |||||
| <property name="ant.package" value="org/apache/tools/todo"/> | <property name="ant.package" value="org/apache/tools/todo"/> | ||||
| <property name="taskdefs.package" value="${ant.package}/taskdefs"/> | <property name="taskdefs.package" value="${ant.package}/taskdefs"/> | ||||
| <property name="antlib.package" value="org/apache/antlib"/> | <property name="antlib.package" value="org/apache/antlib"/> | ||||
| @@ -390,14 +378,6 @@ Legal: | |||||
| </fileset> | </fileset> | ||||
| </antlib-descriptor> | </antlib-descriptor> | ||||
| <antlib-descriptor libName="container" | |||||
| destdir="${gen.dir}" | |||||
| classpathref="project.class.path"> | |||||
| <fileset dir="${java.dir}"> | |||||
| <patternset refid="myrmidon-container.include"/> | |||||
| </fileset> | |||||
| </antlib-descriptor> | |||||
| <antlib-descriptor libName="selftest" | <antlib-descriptor libName="selftest" | ||||
| destdir="${gen.dir}" | destdir="${gen.dir}" | ||||
| classpathref="project.class.path"> | classpathref="project.class.path"> | ||||
| @@ -422,20 +402,6 @@ Legal: | |||||
| <mkdir dir="${build.lib}"/> | <mkdir dir="${build.lib}"/> | ||||
| <mkdir dir="${build.ext}"/> | <mkdir dir="${build.ext}"/> | ||||
| <jar jarfile="${build.bin}/myrmidon-launcher.jar" | |||||
| basedir="${build.classes}" | |||||
| manifest="${manifest.dir}/myrmidon-launcher.mf"> | |||||
| <patternset refid="myrmidon-launcher.include"/> | |||||
| </jar> | |||||
| <antlib-jar jarfile="${build.bin}/lib/myrmidon-container.jar" | |||||
| basedir="${build.classes}" | |||||
| manifest="${manifest.dir}/myrmidon-container.mf" | |||||
| rolesDescriptor="${gen.dir}/container-ant-roles.xml" | |||||
| descriptor="${gen.dir}/container-ant-descriptor.xml" > | |||||
| <patternset refid="myrmidon-container.include"/> | |||||
| </antlib-jar> | |||||
| <antlib-jar jarfile="${build.lib}/myrmidon-framework.jar" | <antlib-jar jarfile="${build.lib}/myrmidon-framework.jar" | ||||
| basedir="${build.classes}" | basedir="${build.classes}" | ||||
| manifest="${manifest.dir}/myrmidon-api.mf" | manifest="${manifest.dir}/myrmidon-api.mf" | ||||
| @@ -1,179 +0,0 @@ | |||||
| /* | |||||
| * 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.components.aspect; | |||||
| import java.util.HashMap; | |||||
| 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.logger.Logger; | |||||
| import org.apache.avalon.framework.parameters.Parameters; | |||||
| import org.apache.myrmidon.api.Task; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.aspects.AspectHandler; | |||||
| import org.apache.myrmidon.aspects.NoopAspectHandler; | |||||
| import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||||
| /** | |||||
| * Manage and propogate Aspects. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultAspectManager | |||||
| implements AspectManager, Initializable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultAspectManager.class ); | |||||
| private HashMap m_aspectMap = new HashMap(); | |||||
| private AspectHandler[] m_aspects = new AspectHandler[ 0 ]; | |||||
| private String[] m_names = new String[ 0 ]; | |||||
| public void initialize() | |||||
| throws Exception | |||||
| { | |||||
| ///UGLY HACK!!!! | |||||
| addAspectHandler( "ant", new NoopAspectHandler() ); | |||||
| addAspectHandler( "doc", new NoopAspectHandler() ); | |||||
| } | |||||
| public synchronized void addAspectHandler( final String name, final AspectHandler handler ) | |||||
| throws TaskException | |||||
| { | |||||
| m_aspectMap.put( name, handler ); | |||||
| rebuildArrays(); | |||||
| } | |||||
| public synchronized void removeAspectHandler( final String name ) | |||||
| throws TaskException | |||||
| { | |||||
| final AspectHandler entry = (AspectHandler)m_aspectMap.remove( name ); | |||||
| if( null == entry ) | |||||
| { | |||||
| final String message = REZ.getString( "no.aspect", name ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| rebuildArrays(); | |||||
| } | |||||
| private void rebuildArrays() | |||||
| { | |||||
| m_aspects = (AspectHandler[])m_aspectMap.values().toArray( m_aspects ); | |||||
| m_names = (String[])m_aspectMap.keySet().toArray( m_names ); | |||||
| } | |||||
| public String[] getNames() | |||||
| { | |||||
| return m_names; | |||||
| } | |||||
| public void dispatchAspectSettings( final String name, | |||||
| final Parameters parameters, | |||||
| final Configuration[] elements ) | |||||
| throws TaskException | |||||
| { | |||||
| final AspectHandler handler = (AspectHandler)m_aspectMap.get( name ); | |||||
| if( null == handler ) | |||||
| { | |||||
| final String message = REZ.getString( "no.aspect", name ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| handler.aspectSettings( parameters, elements ); | |||||
| } | |||||
| public Configuration preCreate( final Configuration configuration ) | |||||
| throws TaskException | |||||
| { | |||||
| Configuration model = configuration; | |||||
| final AspectHandler[] aspects = m_aspects; | |||||
| for( int i = 0; i < aspects.length; i++ ) | |||||
| { | |||||
| model = aspects[ i ].preCreate( model ); | |||||
| } | |||||
| return model; | |||||
| } | |||||
| public void aspectSettings( final Parameters parameters, final Configuration[] elements ) | |||||
| throws TaskException | |||||
| { | |||||
| final String message = REZ.getString( "no.settings" ); | |||||
| throw new UnsupportedOperationException( message ); | |||||
| } | |||||
| public void postCreate( final Task task ) | |||||
| throws TaskException | |||||
| { | |||||
| final AspectHandler[] aspects = m_aspects; | |||||
| for( int i = 0; i < aspects.length; i++ ) | |||||
| { | |||||
| aspects[ i ].postCreate( task ); | |||||
| } | |||||
| } | |||||
| public void preLogEnabled( final Logger logger ) | |||||
| throws TaskException | |||||
| { | |||||
| final AspectHandler[] aspects = m_aspects; | |||||
| for( int i = 0; i < aspects.length; i++ ) | |||||
| { | |||||
| aspects[ i ].preLogEnabled( logger ); | |||||
| } | |||||
| } | |||||
| public void preConfigure( final Configuration taskModel ) | |||||
| throws TaskException | |||||
| { | |||||
| final AspectHandler[] aspects = m_aspects; | |||||
| for( int i = 0; i < aspects.length; i++ ) | |||||
| { | |||||
| aspects[ i ].preConfigure( taskModel ); | |||||
| } | |||||
| } | |||||
| public void preExecute() | |||||
| throws TaskException | |||||
| { | |||||
| final AspectHandler[] aspects = m_aspects; | |||||
| for( int i = 0; i < aspects.length; i++ ) | |||||
| { | |||||
| aspects[ i ].preExecute(); | |||||
| } | |||||
| } | |||||
| public void preDestroy() | |||||
| throws TaskException | |||||
| { | |||||
| final AspectHandler[] aspects = m_aspects; | |||||
| for( int i = 0; i < aspects.length; i++ ) | |||||
| { | |||||
| aspects[ i ].preDestroy(); | |||||
| } | |||||
| } | |||||
| public boolean error( final TaskException te ) | |||||
| throws TaskException | |||||
| { | |||||
| final AspectHandler[] aspects = m_aspects; | |||||
| for( int i = 0; i < aspects.length; i++ ) | |||||
| { | |||||
| final boolean isError = aspects[ i ].error( te ); | |||||
| if( isError ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| } | |||||
| @@ -1,2 +0,0 @@ | |||||
| no.aspect=No such aspect with name {0}. | |||||
| no.settings=Can not provide Settings to AspectManager. | |||||
| @@ -1,227 +0,0 @@ | |||||
| /* | |||||
| * 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.components.builder; | |||||
| import java.io.InputStream; | |||||
| import java.net.URL; | |||||
| import java.util.Properties; | |||||
| import javax.xml.parsers.SAXParser; | |||||
| import javax.xml.parsers.SAXParserFactory; | |||||
| import javax.xml.transform.Transformer; | |||||
| import javax.xml.transform.TransformerFactory; | |||||
| import javax.xml.transform.sax.SAXResult; | |||||
| import javax.xml.transform.stream.StreamSource; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||||
| import org.apache.avalon.framework.parameters.Parameterizable; | |||||
| import org.apache.avalon.framework.parameters.Parameters; | |||||
| import org.xml.sax.SAXException; | |||||
| import org.xml.sax.XMLReader; | |||||
| /** | |||||
| * Default implementation to construct project from a build file. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * @ant.type type="project-builder" name="ati" | |||||
| */ | |||||
| public class ATIProjectBuilder | |||||
| extends DefaultProjectBuilder | |||||
| implements Parameterizable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( ATIProjectBuilder.class ); | |||||
| private Parameters m_parameters; | |||||
| public void parameterize( final Parameters parameters ) | |||||
| { | |||||
| m_parameters = parameters; | |||||
| } | |||||
| protected void process( final URL sourceID, | |||||
| final SAXConfigurationHandler handler ) | |||||
| throws Exception | |||||
| { | |||||
| final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||||
| final SAXParser saxParser = saxParserFactory.newSAXParser(); | |||||
| final XMLReader reader = saxParser.getXMLReader(); | |||||
| reader.setFeature( "http://xml.org/sax/features/validation", false ); | |||||
| reader.setErrorHandler( handler ); | |||||
| final ReactorPIHandler reactorHandler = new ReactorPIHandler(); | |||||
| reader.setContentHandler( reactorHandler ); | |||||
| try | |||||
| { | |||||
| reader.parse( sourceID.toString() ); | |||||
| } | |||||
| catch( final StopParsingException spe ) | |||||
| { | |||||
| //Ignore me | |||||
| } | |||||
| Transformer transformer = null; | |||||
| final int size = reactorHandler.getPICount(); | |||||
| for( int i = 0; i < size; i++ ) | |||||
| { | |||||
| final String target = reactorHandler.getTarget( i ); | |||||
| final String data = reactorHandler.getData( i ); | |||||
| if( target.equals( "xsl-param" ) ) | |||||
| { | |||||
| handleParameter( data ); | |||||
| } | |||||
| else if( target.equals( "xsl-params" ) ) | |||||
| { | |||||
| handleParameters( data, sourceID ); | |||||
| } | |||||
| else if( target.equals( "xsl-stylesheet" ) ) | |||||
| { | |||||
| if( null != transformer ) | |||||
| { | |||||
| final String message = REZ.getString( "ati.two.stylesheet.pis" ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| final TransformerFactory factory = TransformerFactory.newInstance(); | |||||
| final String stylesheet = getStylesheet( data, sourceID ); | |||||
| transformer = factory.newTransformer( new StreamSource( stylesheet ) ); | |||||
| } | |||||
| } | |||||
| if( null == transformer ) | |||||
| { | |||||
| reader.setContentHandler( handler ); | |||||
| reader.parse( sourceID.toString() ); | |||||
| } | |||||
| else | |||||
| { | |||||
| final String[] names = m_parameters.getNames(); | |||||
| for( int i = 0; i < names.length; i++ ) | |||||
| { | |||||
| final String name = names[ i ]; | |||||
| final String value = m_parameters.getParameter( name ); | |||||
| transformer.setParameter( name, value ); | |||||
| } | |||||
| final SAXResult result = new SAXResult( handler ); | |||||
| transformer.transform( new StreamSource( sourceID.toString() ), result ); | |||||
| //transformer.transform( new StreamSource( sourceID.toString() ), | |||||
| //new StreamResult( System.out ) ); | |||||
| } | |||||
| } | |||||
| private void handleParameter( final String data ) | |||||
| throws SAXException | |||||
| { | |||||
| int index = data.indexOf( '\"' ); | |||||
| if( -1 == index ) | |||||
| { | |||||
| final String message = REZ.getString( "ati.param.error" ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| index = data.indexOf( '\"', index + 1 ); | |||||
| if( -1 == index ) | |||||
| { | |||||
| final String message = REZ.getString( "ati.param.error" ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| //split between two "attributes" occurs on index | |||||
| final String[] name = parseAttribute( data.substring( 0, index + 1 ) ); | |||||
| final String[] value = parseAttribute( data.substring( index + 1 ).trim() ); | |||||
| if( !name[ 0 ].equals( "name" ) || !value[ 0 ].equals( "value" ) ) | |||||
| { | |||||
| final String message = REZ.getString( "ati.param.error" ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| m_parameters.setParameter( name[ 1 ], value[ 1 ] ); | |||||
| } | |||||
| private void handleParameters( final String data, final URL baseSource ) | |||||
| throws SAXException | |||||
| { | |||||
| final String[] params = parseAttribute( data ); | |||||
| if( !params[ 0 ].equals( "location" ) ) | |||||
| { | |||||
| final String message = REZ.getString( "ati.params.error" ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| try | |||||
| { | |||||
| final Properties properties = new Properties(); | |||||
| final URL url = new URL( baseSource, params[ 1 ] ); | |||||
| final InputStream input = url.openStream(); | |||||
| properties.load( input ); | |||||
| final Parameters parameters = Parameters.fromProperties( properties ); | |||||
| m_parameters.merge( parameters ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "ati.loading-params.error", params[ 1 ], e ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| } | |||||
| private String getStylesheet( final String data, final URL baseSource ) | |||||
| throws SAXException | |||||
| { | |||||
| final String[] stylesheet = parseAttribute( data ); | |||||
| if( !stylesheet[ 0 ].equals( "href" ) ) | |||||
| { | |||||
| final String message = REZ.getString( "ati.style.error" ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| try | |||||
| { | |||||
| return new URL( baseSource, stylesheet[ 1 ] ).toString(); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ati.loading-style.error", stylesheet[ 1 ], e ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| } | |||||
| private String[] parseAttribute( final String data ) | |||||
| throws SAXException | |||||
| { | |||||
| //name="value" | |||||
| int index = data.indexOf( '=' ); | |||||
| if( -1 == index ) | |||||
| { | |||||
| final String message = REZ.getString( "ati.attribue-expected.error", data ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| final int size = data.length(); | |||||
| if( '\"' != data.charAt( index + 1 ) || | |||||
| '\"' != data.charAt( size - 1 ) || | |||||
| size - 1 == index ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ati.attribue-unquoted.error", data.substring( 0, index ) ); | |||||
| throw new SAXException( message ); | |||||
| } | |||||
| final String[] result = new String[ 2 ]; | |||||
| result[ 0 ] = data.substring( 0, index ); | |||||
| result[ 1 ] = data.substring( index + 2, size - 1 ); | |||||
| return result; | |||||
| } | |||||
| } | |||||
| @@ -1,247 +0,0 @@ | |||||
| /* | |||||
| * 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.components.builder; | |||||
| import java.util.HashSet; | |||||
| import java.util.Set; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.configuration.DefaultConfiguration; | |||||
| import org.apache.myrmidon.interfaces.builder.ProjectException; | |||||
| /** | |||||
| * A simple ProjectBuilder, which programmatically converts an Ant1 Project | |||||
| * configuration into a Myrmidon one. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | |||||
| * @ant.type type="project-builder" name="xml" | |||||
| * @ant.type type="project-builder" name="ant" | |||||
| * @ant.type type="project-builder" name="default" | |||||
| */ | |||||
| public class ConvertingProjectBuilder | |||||
| extends DefaultProjectBuilder | |||||
| { | |||||
| private static final String VERSION_ATTRIBUTE = "version"; | |||||
| /** | |||||
| * Builds a Configuration from an Ant1 project file, converting it | |||||
| * into a valid Myrmidon Project. | |||||
| * @param systemID the xml Systemid of the project file. | |||||
| * @return the configured project | |||||
| * @throws ProjectException if an error occurs parsing the project file | |||||
| */ | |||||
| protected Configuration parseProject( final String systemID ) | |||||
| throws ProjectException | |||||
| { | |||||
| final Configuration originalConfig = super.parseProject( systemID ); | |||||
| // Check the version, if it's present, just use this config. | |||||
| // TODO: check for version < 2.0 | |||||
| if( originalConfig.getAttribute( VERSION_ATTRIBUTE, null ) != null ) | |||||
| { | |||||
| return originalConfig; | |||||
| } | |||||
| // Convert the config by prepending "ant1." on tasks, | |||||
| // and using <if> tasks instead of target 'if=' and 'unless=' | |||||
| final DefaultConfiguration newConfig = copyConfiguration( originalConfig ); | |||||
| // Put a new version attribute. | |||||
| newConfig.setAttribute( VERSION_ATTRIBUTE, "2.0" ); | |||||
| // Copy the remaining attributes. | |||||
| final Set omitAttributes = new HashSet(); | |||||
| omitAttributes.add( VERSION_ATTRIBUTE ); | |||||
| copyAttributes( originalConfig, newConfig, omitAttributes ); | |||||
| // Now copy/convert the children | |||||
| final Configuration[] children = originalConfig.getChildren(); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | |||||
| final Configuration child = children[ i ]; | |||||
| if( child.getName().equals( "target" ) ) | |||||
| { | |||||
| newConfig.addChild( convertTarget( child ) ); | |||||
| } | |||||
| else | |||||
| { | |||||
| newConfig.addChild( convertTask( child ) ); | |||||
| } | |||||
| } | |||||
| return newConfig; | |||||
| } | |||||
| /** | |||||
| * Converts Configuration for an Ant1 Target into a Myrmidon version. | |||||
| * @param originalTarget The Ant1 Target | |||||
| * @return the converted target | |||||
| */ | |||||
| private Configuration convertTarget( final Configuration originalTarget ) | |||||
| { | |||||
| final DefaultConfiguration newTarget = copyConfiguration( originalTarget ); | |||||
| // Copy all attributes except 'if' and 'unless' | |||||
| final Set omitAttributes = new HashSet(); | |||||
| omitAttributes.add( "if" ); | |||||
| omitAttributes.add( "unless" ); | |||||
| copyAttributes( originalTarget, newTarget, omitAttributes ); | |||||
| DefaultConfiguration containerElement = newTarget; | |||||
| // For 'if="prop-name"', replace with <if> task. | |||||
| final String ifAttrib = originalTarget.getAttribute( "if", null ); | |||||
| if ( ifAttrib != null ) | |||||
| { | |||||
| final DefaultConfiguration ifElement = | |||||
| buildIfElement( ifAttrib, false, originalTarget.getLocation() ); | |||||
| containerElement.addChild( ifElement ); | |||||
| // Treat the ifElement as the enclosing target. | |||||
| containerElement = ifElement; | |||||
| } | |||||
| // For 'unless="prop-name"', replace with <if> task (negated). | |||||
| final String unlessAttrib = originalTarget.getAttribute( "unless", null ); | |||||
| if ( unlessAttrib != null ) | |||||
| { | |||||
| final DefaultConfiguration unlessElement = | |||||
| buildIfElement( unlessAttrib, true, originalTarget.getLocation() ); | |||||
| containerElement.addChild( unlessElement ); | |||||
| // Treat the unlessElement as the enclosing target. | |||||
| containerElement = unlessElement; | |||||
| } | |||||
| // Now copy in converted tasks. | |||||
| final Configuration[] tasks = originalTarget.getChildren(); | |||||
| for( int i = 0; i < tasks.length; i++ ) | |||||
| { | |||||
| containerElement.addChild( convertTask( tasks[ i ] ) ); | |||||
| } | |||||
| return newTarget; | |||||
| } | |||||
| /** | |||||
| * Builds configuration for an <if> task, to replace a "if" or "unless" | |||||
| * attribute on a Ant1 target. | |||||
| * @param ifProperty the name of the property from the Ant1 attribute. | |||||
| * @param unless if the attribute is actually an "unless" attribute. | |||||
| * @param location the configuration location to use | |||||
| * @return The configuration for an <if> task | |||||
| */ | |||||
| private DefaultConfiguration buildIfElement( final String ifProperty, | |||||
| final boolean unless, | |||||
| final String location ) | |||||
| { | |||||
| // <if> | |||||
| // <condition> | |||||
| // <is-set property="prop-name"/> | |||||
| // </condition> | |||||
| // .. tasks | |||||
| // </if> | |||||
| final DefaultConfiguration isSetElement = | |||||
| new DefaultConfiguration( "is-set", location ); | |||||
| isSetElement.setAttribute( "property", ifProperty ); | |||||
| final DefaultConfiguration conditionElement = | |||||
| new DefaultConfiguration( "condition", location ); | |||||
| if ( unless ) | |||||
| { | |||||
| // Surround <is-set> with <not> | |||||
| final DefaultConfiguration notElement = | |||||
| new DefaultConfiguration( "not", location ); | |||||
| notElement.addChild( isSetElement ); | |||||
| conditionElement.addChild( notElement ); | |||||
| } | |||||
| else | |||||
| { | |||||
| conditionElement.addChild( isSetElement ); | |||||
| } | |||||
| final DefaultConfiguration ifElement = | |||||
| new DefaultConfiguration( "if", location ); | |||||
| ifElement.addChild( conditionElement ); | |||||
| return ifElement; | |||||
| } | |||||
| /** | |||||
| * Converts Configuration for an Ant1 Task into a Myrmidon version. | |||||
| * @param originalTask The Ant1 Task | |||||
| * @return the converted task | |||||
| */ | |||||
| private Configuration convertTask( final Configuration originalTask ) | |||||
| { | |||||
| // Create a new configuration with the "ant1." prefix. | |||||
| final String newTaskName = "ant1." + originalTask.getName(); | |||||
| final DefaultConfiguration newTask = | |||||
| new DefaultConfiguration( newTaskName, originalTask.getLocation() ); | |||||
| // Copy all attributes and elements of the task. | |||||
| copyAttributes( originalTask, newTask, new HashSet() ); | |||||
| copyChildren( originalTask, newTask ); | |||||
| return newTask; | |||||
| } | |||||
| /** | |||||
| * Copies all child elements from one configuration to another | |||||
| * @param from Configuration to copy from | |||||
| * @param to Configuration to copy to | |||||
| */ | |||||
| private void copyChildren( final Configuration from, | |||||
| final DefaultConfiguration to ) | |||||
| { | |||||
| final Configuration[] children = from.getChildren(); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | |||||
| to.addChild( children[ i ] ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Copies all attributes from one configuration to another, excluding | |||||
| * specified attribute names. | |||||
| * @param from Configuration to copy from | |||||
| * @param to Configuration to copy to | |||||
| * @param omitAttributes a Set of attribute names to exclude | |||||
| */ | |||||
| private void copyAttributes( final Configuration from, | |||||
| final DefaultConfiguration to, | |||||
| final Set omitAttributes ) | |||||
| { | |||||
| // Copy other attributes | |||||
| final String[] attribs = from.getAttributeNames(); | |||||
| for( int i = 0; i < attribs.length; i++ ) | |||||
| { | |||||
| final String name = attribs[ i ]; | |||||
| if( omitAttributes.contains( name ) ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| final String value = from.getAttribute( name, "" ); | |||||
| to.setAttribute( name, value ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a DefaultConfiguration with the same name and location as | |||||
| * the one supplied. | |||||
| * @param originalConfig the COnfiguration to copy. | |||||
| * @return the new Configuration | |||||
| */ | |||||
| private DefaultConfiguration copyConfiguration( final Configuration originalConfig ) | |||||
| { | |||||
| return new DefaultConfiguration( originalConfig.getName(), | |||||
| originalConfig.getLocation() ); | |||||
| } | |||||
| } | |||||
| @@ -1,229 +0,0 @@ | |||||
| /* | |||||
| * 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.components.builder; | |||||
| import java.io.File; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.myrmidon.interfaces.model.Project; | |||||
| import org.apache.myrmidon.interfaces.model.Target; | |||||
| import org.apache.myrmidon.interfaces.model.TypeLib; | |||||
| /** | |||||
| * Default project implementation. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultProject | |||||
| implements Project | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultProject.class ); | |||||
| ///The imports | |||||
| private final ArrayList m_imports = new ArrayList(); | |||||
| ///The projects refferred to by this project | |||||
| private final HashMap m_projects = new HashMap(); | |||||
| ///The targets contained by this project | |||||
| private final HashMap m_targets = new HashMap(); | |||||
| ///The implicit target (not present in m_targets) | |||||
| private Target m_implicitTarget; | |||||
| ///The name of the default target | |||||
| private String m_defaultTarget; | |||||
| ///The base directory of project | |||||
| private File m_baseDirectory; | |||||
| ///The project name | |||||
| private String m_name; | |||||
| /** | |||||
| * @return the project name. | |||||
| */ | |||||
| public String getProjectName() | |||||
| { | |||||
| return m_name; | |||||
| } | |||||
| /** | |||||
| * Sets the project name. | |||||
| * @param name the project name | |||||
| */ | |||||
| public void setProjectName( String name ) | |||||
| { | |||||
| m_name = name; | |||||
| } | |||||
| /** | |||||
| * Get the imports for project. | |||||
| * | |||||
| * @return the imports | |||||
| */ | |||||
| public TypeLib[] getTypeLibs() | |||||
| { | |||||
| return (TypeLib[])m_imports.toArray( new TypeLib[ 0 ] ); | |||||
| } | |||||
| /** | |||||
| * Get names of projects referred to by this project. | |||||
| * | |||||
| * @return the names | |||||
| */ | |||||
| public String[] getProjectNames() | |||||
| { | |||||
| return (String[])m_projects.keySet().toArray( new String[ 0 ] ); | |||||
| } | |||||
| /** | |||||
| * Retrieve project reffered to by this project. | |||||
| * | |||||
| * @param name the project name | |||||
| * @return the Project or null if none by that name | |||||
| */ | |||||
| public Project getProject( final String name ) | |||||
| { | |||||
| return (Project)m_projects.get( name ); | |||||
| } | |||||
| /** | |||||
| * Retrieve base directory of project. | |||||
| * | |||||
| * @return the projects base directory | |||||
| */ | |||||
| public final File getBaseDirectory() | |||||
| { | |||||
| return m_baseDirectory; | |||||
| } | |||||
| /** | |||||
| * Retrieve implicit target. | |||||
| * The implicit target contains all the top level tasks. | |||||
| * | |||||
| * @return the Target | |||||
| */ | |||||
| public final Target getImplicitTarget() | |||||
| { | |||||
| return m_implicitTarget; | |||||
| } | |||||
| /** | |||||
| * Set ImplicitTarget. | |||||
| * | |||||
| * @param target the implicit target | |||||
| */ | |||||
| public final void setImplicitTarget( final Target target ) | |||||
| { | |||||
| m_implicitTarget = target; | |||||
| } | |||||
| /** | |||||
| * Retrieve a target by name. | |||||
| * | |||||
| * @param targetName the name of target | |||||
| * @return the Target or null if no target exists with name | |||||
| */ | |||||
| public final Target getTarget( final String targetName ) | |||||
| { | |||||
| return (Target)m_targets.get( targetName ); | |||||
| } | |||||
| /** | |||||
| * Get name of default target. | |||||
| * | |||||
| * @return the default target name | |||||
| */ | |||||
| public final String getDefaultTargetName() | |||||
| { | |||||
| return m_defaultTarget; | |||||
| } | |||||
| /** | |||||
| * Retrieve names of all targets in project. | |||||
| * | |||||
| * @return an array target names | |||||
| */ | |||||
| public final String[] getTargetNames() | |||||
| { | |||||
| return (String[])m_targets.keySet().toArray( new String[ 0 ] ); | |||||
| } | |||||
| /** | |||||
| * Set DefaultTargetName. | |||||
| * | |||||
| * @param defaultTarget the default target name | |||||
| */ | |||||
| public final void setDefaultTargetName( final String defaultTarget ) | |||||
| { | |||||
| m_defaultTarget = defaultTarget; | |||||
| } | |||||
| /** | |||||
| * Sets the project base directory. | |||||
| * @param baseDirectory the base directory for the project | |||||
| */ | |||||
| public final void setBaseDirectory( final File baseDirectory ) | |||||
| { | |||||
| m_baseDirectory = baseDirectory; | |||||
| } | |||||
| /** | |||||
| * Adds a type library import to the project. | |||||
| * @param typeLib the type library | |||||
| */ | |||||
| public final void addTypeLib( final TypeLib typeLib ) | |||||
| { | |||||
| m_imports.add( typeLib ); | |||||
| } | |||||
| /** | |||||
| * Add a target. | |||||
| * | |||||
| * @param name the name of target | |||||
| * @param target the Target | |||||
| * @exception IllegalArgumentException if target already exists with same name | |||||
| */ | |||||
| public final void addTarget( final String name, final Target target ) | |||||
| { | |||||
| if( null != m_targets.get( name ) ) | |||||
| { | |||||
| final String message = REZ.getString( "duplicate-target.error", name ); | |||||
| throw new IllegalArgumentException( message ); | |||||
| } | |||||
| else | |||||
| { | |||||
| m_targets.put( name, target ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Add a project reference. | |||||
| * | |||||
| * @param name the name of target | |||||
| * @param project the Project | |||||
| * @exception IllegalArgumentException if project already exists with same name | |||||
| */ | |||||
| public final void addProject( final String name, final Project project ) | |||||
| { | |||||
| if( null != m_projects.get( name ) ) | |||||
| { | |||||
| final String message = REZ.getString( "duplicate-project.error", name ); | |||||
| throw new IllegalArgumentException( message ); | |||||
| } | |||||
| else | |||||
| { | |||||
| m_projects.put( name, project ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,553 +0,0 @@ | |||||
| /* | |||||
| * 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.components.builder; | |||||
| import java.io.File; | |||||
| import java.util.ArrayList; | |||||
| 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.excalibur.io.FileUtil; | |||||
| import org.apache.avalon.excalibur.util.StringUtil; | |||||
| import org.apache.avalon.framework.Version; | |||||
| 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.interfaces.builder.ProjectBuilder; | |||||
| import org.apache.myrmidon.interfaces.builder.ProjectException; | |||||
| import org.apache.myrmidon.interfaces.model.DefaultNameValidator; | |||||
| import org.apache.myrmidon.interfaces.model.Dependency; | |||||
| import org.apache.myrmidon.interfaces.model.Project; | |||||
| import org.apache.myrmidon.interfaces.model.Target; | |||||
| import org.apache.myrmidon.interfaces.model.TypeLib; | |||||
| import org.xml.sax.XMLReader; | |||||
| /** | |||||
| * Default implementation to construct project from a build file. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | |||||
| * @ant.type type="project-builder" name="ant2" | |||||
| */ | |||||
| public class DefaultProjectBuilder | |||||
| extends AbstractLogEnabled | |||||
| implements ProjectBuilder | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultProjectBuilder.class ); | |||||
| private static final Version VERSION = new Version( 2, 0, 0 ); | |||||
| private static final int PROJECT_REFERENCES = 0; | |||||
| private static final int LIBRARY_IMPORTS = 1; | |||||
| private static final int IMPLICIT_TASKS = 2; | |||||
| private static final int TARGETS = 3; | |||||
| // Use a name validator with the default rules. | |||||
| private DefaultNameValidator m_nameValidator = new DefaultNameValidator(); | |||||
| /** | |||||
| * build a project from file. | |||||
| * | |||||
| * @param source the source | |||||
| * @return the constructed Project | |||||
| * @exception ProjectException if an error occurs | |||||
| */ | |||||
| public Project build( final String source ) | |||||
| throws ProjectException | |||||
| { | |||||
| final File file = new File( source ); | |||||
| return build( file, new HashMap() ); | |||||
| } | |||||
| private Project build( final File file, final HashMap projects ) | |||||
| throws ProjectException | |||||
| { | |||||
| try | |||||
| { | |||||
| // Check for cached project | |||||
| final String systemID = extractURL( file ); | |||||
| final Project result = (Project)projects.get( systemID ); | |||||
| if( null != result ) | |||||
| { | |||||
| return result; | |||||
| } | |||||
| // Parse the project file | |||||
| final Configuration configuration = parseProject( systemID ); | |||||
| // Build the project model and add to cache | |||||
| final DefaultProject project = buildProject( file, configuration ); | |||||
| projects.put( systemID, project ); | |||||
| // Build using all top-level attributes | |||||
| buildTopLevelProject( project, configuration, projects ); | |||||
| return project; | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.project-build.error", | |||||
| file.getAbsolutePath() ); | |||||
| throw new ProjectException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Builds a project configuration from a build file. | |||||
| * @param systemID the XML system id of the build file | |||||
| * @return the project configuration | |||||
| * @throws ProjectException on parse error | |||||
| */ | |||||
| protected Configuration parseProject( final String systemID ) | |||||
| throws ProjectException | |||||
| { | |||||
| try | |||||
| { | |||||
| final SAXConfigurationHandler handler = new SAXConfigurationHandler(); | |||||
| 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 ); | |||||
| parser.setFeature( "http://xml.org/sax/features/namespaces", false ); | |||||
| //parser.setFeature( "http://xml.org/sax/features/validation", false ); | |||||
| parser.setContentHandler( handler ); | |||||
| parser.setErrorHandler( handler ); | |||||
| parser.parse( systemID ); | |||||
| return handler.getConfiguration(); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.project-parse.error" ); | |||||
| throw new ProjectException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * build project from configuration. | |||||
| * | |||||
| * @param file the file from which configuration was loaded | |||||
| * @param configuration the configuration loaded | |||||
| * @return the created Project | |||||
| * @exception ProjectException if an error occurs building the project | |||||
| */ | |||||
| private DefaultProject buildProject( final File file, | |||||
| final Configuration configuration ) | |||||
| throws ProjectException | |||||
| { | |||||
| if( !configuration.getName().equals( "project" ) ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.no-project-element.error" ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| //get project-level attributes | |||||
| final String projectName = getProjectName( configuration, file ); | |||||
| final String baseDirectoryName = configuration.getAttribute( "basedir", null ); | |||||
| final String defaultTarget = configuration.getAttribute( "default", "main" ); | |||||
| final Version version = getVersion( configuration ); | |||||
| if( !VERSION.complies( version ) ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.bad-version.error", VERSION, version ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| //determine base directory for project. Use the directory containing | |||||
| //the build file as the default. | |||||
| File baseDirectory = file.getParentFile(); | |||||
| if( baseDirectoryName != null ) | |||||
| { | |||||
| baseDirectory = FileUtil.resolveFile( baseDirectory, baseDirectoryName ); | |||||
| } | |||||
| baseDirectory = baseDirectory.getAbsoluteFile(); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.project-banner.notice", | |||||
| file, baseDirectory ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| //create project and ... | |||||
| final DefaultProject project = new DefaultProject(); | |||||
| project.setProjectName( projectName ); | |||||
| project.setDefaultTargetName( defaultTarget ); | |||||
| project.setBaseDirectory( baseDirectory ); | |||||
| return project; | |||||
| } | |||||
| /** | |||||
| * Get the project name from the configuration, or create a default name if none | |||||
| * was supplied. | |||||
| */ | |||||
| private String getProjectName( final Configuration configuration, | |||||
| final File file ) | |||||
| throws ProjectException | |||||
| { | |||||
| String projectName = configuration.getAttribute( "name", null ); | |||||
| if( projectName == null ) | |||||
| { | |||||
| // Create a name based on the file name. | |||||
| String fileNameBase = FileUtil.removeExtension( file.getName() ); | |||||
| try | |||||
| { | |||||
| projectName = m_nameValidator.makeValidName( fileNameBase ); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| String message = REZ.getString( "ant.project-create-name.error" ); | |||||
| throw new ProjectException( message, e ); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| // Make sure the supplied name is valid. | |||||
| try | |||||
| { | |||||
| m_nameValidator.validate( projectName ); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| String message = REZ.getString( "ant.project-bad-name.error" ); | |||||
| throw new ProjectException( message, e ); | |||||
| } | |||||
| } | |||||
| return projectName; | |||||
| } | |||||
| /** | |||||
| * Retrieve the version attribute from the specified configuration element. | |||||
| * Throw exceptions with meaningful errors if malformed or missing. | |||||
| */ | |||||
| private Version getVersion( final Configuration configuration ) | |||||
| throws ProjectException | |||||
| { | |||||
| try | |||||
| { | |||||
| final String versionString = configuration.getAttribute( "version" ); | |||||
| return parseVersion( versionString ); | |||||
| } | |||||
| catch( final ConfigurationException ce ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.version-missing.error" ); | |||||
| throw new ProjectException( message, ce ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Utility function to extract version | |||||
| */ | |||||
| private Version parseVersion( final String versionString ) | |||||
| throws ProjectException | |||||
| { | |||||
| try | |||||
| { | |||||
| return Version.getVersion( versionString ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.malformed.version", versionString ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Handle all top level elements in configuration. | |||||
| * | |||||
| * @param project the project | |||||
| * @param configuration the Configuration | |||||
| * @exception ProjectException if an error occurs | |||||
| */ | |||||
| private void buildTopLevelProject( final DefaultProject project, | |||||
| final Configuration configuration, | |||||
| final HashMap projects ) | |||||
| throws ProjectException | |||||
| { | |||||
| final ArrayList implicitTaskList = new ArrayList(); | |||||
| final Configuration[] children = configuration.getChildren(); | |||||
| int state = PROJECT_REFERENCES; | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | |||||
| final Configuration element = children[ i ]; | |||||
| final String name = element.getName(); | |||||
| if( PROJECT_REFERENCES == state ) | |||||
| { | |||||
| if( name.equals( "projectref" ) ) | |||||
| { | |||||
| buildProjectRef( project, element, projects ); | |||||
| continue; | |||||
| } | |||||
| else | |||||
| { | |||||
| state = LIBRARY_IMPORTS; | |||||
| } | |||||
| } | |||||
| if( LIBRARY_IMPORTS == state ) | |||||
| { | |||||
| if( name.equals( "import" ) ) | |||||
| { | |||||
| buildTypeLib( project, element ); | |||||
| continue; | |||||
| } | |||||
| else | |||||
| { | |||||
| state = IMPLICIT_TASKS; | |||||
| } | |||||
| } | |||||
| if( IMPLICIT_TASKS == state ) | |||||
| { | |||||
| //Check for any implicit tasks here | |||||
| if( !name.equals( "target" ) ) | |||||
| { | |||||
| implicitTaskList.add( element ); | |||||
| continue; | |||||
| } | |||||
| else | |||||
| { | |||||
| state = TARGETS; | |||||
| } | |||||
| } | |||||
| if( name.equals( "target" ) ) | |||||
| { | |||||
| buildTarget( project, element ); | |||||
| } | |||||
| else | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.unknown-toplevel-element.error", name, | |||||
| element.getLocation() ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| } | |||||
| final Configuration[] implicitTasks = | |||||
| (Configuration[])implicitTaskList.toArray( new Configuration[ 0 ] ); | |||||
| final Target implicitTarget = new Target( implicitTasks, null ); | |||||
| project.setImplicitTarget( implicitTarget ); | |||||
| } | |||||
| private void buildProjectRef( final DefaultProject project, | |||||
| final Configuration element, | |||||
| final HashMap projects ) | |||||
| throws ProjectException | |||||
| { | |||||
| final String name = element.getAttribute( "name", null ); | |||||
| final String location = element.getAttribute( "location", null ); | |||||
| if( null == name ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.projectref-no-name.error", | |||||
| element.getLocation() ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| try | |||||
| { | |||||
| m_nameValidator.validate( name ); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.projectref-bad-name.error", | |||||
| element.getLocation() ); | |||||
| throw new ProjectException( message, e ); | |||||
| } | |||||
| if( null == location ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.projectref-no-location.error", | |||||
| element.getLocation() ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| // Build the URL of the referenced projects | |||||
| final File baseDirectory = project.getBaseDirectory(); | |||||
| final File file = FileUtil.resolveFile( baseDirectory, location ); | |||||
| // Locate the referenced project, building it if necessary | |||||
| final Project other = build( file, projects ); | |||||
| // Add the reference | |||||
| project.addProject( name, other ); | |||||
| } | |||||
| /** | |||||
| * Validates a project file name, and builds the canonical URL for it. | |||||
| */ | |||||
| private String extractURL( final File file ) throws ProjectException | |||||
| { | |||||
| if( ! file.isFile() ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.no-project-file.error" ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| try | |||||
| { | |||||
| return file.getCanonicalFile().toURL().toString(); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.project-unexpected.error" ); | |||||
| throw new ProjectException( message, e ); | |||||
| } | |||||
| } | |||||
| private void buildTypeLib( final DefaultProject project, | |||||
| final Configuration element ) | |||||
| throws ProjectException | |||||
| { | |||||
| final String library = element.getAttribute( "library", null ); | |||||
| final String name = element.getAttribute( "name", null ); | |||||
| final String type = element.getAttribute( "type", null ); | |||||
| if( null == library ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.import-no-library.error", element.getLocation() ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| if( null == name || null == type ) | |||||
| { | |||||
| if( null != name || null != type ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.import-malformed.error", element.getLocation() ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| } | |||||
| project.addTypeLib( new TypeLib( library, type, name ) ); | |||||
| } | |||||
| /** | |||||
| * Build a target from configuration. | |||||
| * | |||||
| * @param project the project | |||||
| * @param target the Configuration | |||||
| */ | |||||
| private void buildTarget( final DefaultProject project, final Configuration target ) | |||||
| throws ProjectException | |||||
| { | |||||
| final String name = target.getAttribute( "name", null ); | |||||
| final String depends = target.getAttribute( "depends", null ); | |||||
| verifyTargetName( name, target ); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.target-parse.notice", name ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| final Dependency[] dependencies = buildDependsList( depends, target ); | |||||
| final Target defaultTarget = new Target( target.getChildren(), dependencies ); | |||||
| //add target to project | |||||
| project.addTarget( name, defaultTarget ); | |||||
| } | |||||
| private void verifyTargetName( final String name, final Configuration target ) | |||||
| throws ProjectException | |||||
| { | |||||
| if( null == name ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.target-noname.error", target.getLocation() ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| try | |||||
| { | |||||
| m_nameValidator.validate( name ); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "ant.target-bad-name.error", target.getLocation() ); | |||||
| throw new ProjectException( message, e ); | |||||
| } | |||||
| } | |||||
| private Dependency[] buildDependsList( final String depends, | |||||
| final Configuration target ) | |||||
| throws ProjectException | |||||
| { | |||||
| //apply depends attribute | |||||
| if( null == depends ) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| final String[] elements = StringUtil.split( depends, "," ); | |||||
| final ArrayList dependsList = new ArrayList(); | |||||
| for( int i = 0; i < elements.length; i++ ) | |||||
| { | |||||
| final String dependency = elements[ i ].trim(); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.target-dependency.notice", | |||||
| dependency ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| // Split project->target dependencies | |||||
| final int sep = dependency.indexOf( "->" ); | |||||
| final String projectName; | |||||
| final String targetName; | |||||
| if( sep != -1 ) | |||||
| { | |||||
| projectName = dependency.substring( 0, sep ); | |||||
| targetName = dependency.substring( sep + 2 ); | |||||
| } | |||||
| else | |||||
| { | |||||
| projectName = null; | |||||
| targetName = dependency; | |||||
| } | |||||
| if( targetName.length() == 0 || | |||||
| ( projectName != null && projectName.length() == 0 ) ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.target-bad-dependency.error", | |||||
| target.getName(), | |||||
| target.getLocation() ); | |||||
| throw new ProjectException( message ); | |||||
| } | |||||
| dependsList.add( new Dependency( projectName, targetName ) ); | |||||
| } | |||||
| return (Dependency[])dependsList.toArray( new Dependency[dependsList.size() ] ); | |||||
| } | |||||
| } | |||||
| @@ -1,60 +0,0 @@ | |||||
| /* | |||||
| * 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.components.builder; | |||||
| import java.util.ArrayList; | |||||
| import org.xml.sax.Attributes; | |||||
| import org.xml.sax.SAXException; | |||||
| import org.xml.sax.helpers.DefaultHandler; | |||||
| /** | |||||
| * Handler that reacts to PIs before first element. | |||||
| * Have to do it this way as there doesn't seem to be a *safe* way | |||||
| * of redirecting content handlers at runtime while using transformers. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class ReactorPIHandler | |||||
| extends DefaultHandler | |||||
| { | |||||
| private ArrayList m_targets = new ArrayList(); | |||||
| private ArrayList m_data = new ArrayList(); | |||||
| public int getPICount() | |||||
| { | |||||
| return m_targets.size(); | |||||
| } | |||||
| public String getTarget( final int index ) | |||||
| { | |||||
| return (String)m_targets.get( index ); | |||||
| } | |||||
| public String getData( final int index ) | |||||
| { | |||||
| return (String)m_data.get( index ); | |||||
| } | |||||
| public void processingInstruction( final String target, final String data ) | |||||
| throws SAXException | |||||
| { | |||||
| m_targets.add( target ); | |||||
| m_data.add( data ); | |||||
| } | |||||
| public void startElement( final String uri, | |||||
| final String localName, | |||||
| final String qName, | |||||
| final Attributes atts ) | |||||
| throws SAXException | |||||
| { | |||||
| //Workaround to stop SAX pipeline | |||||
| throw new StopParsingException(); | |||||
| } | |||||
| } | |||||
| @@ -1,37 +0,0 @@ | |||||
| ati.two.stylesheet.pis=Build file can not contain two xsl-stylesheet PIs. | |||||
| ati.params.error=Malformed PI: expected <?xsl-params location=\"myparams.properties\"?> | |||||
| ati.param.error=Malformed PI: expected <?xsl-param name=\"foo\" value=\"bar\"?> | |||||
| ati.style.error=Malformed PI: expected <?xsl-params href=\"mystylesheet.xsl\"?> | |||||
| ati.loading-params.error=Error loading parameters {0}. Reason: {1}. | |||||
| ati.loading-style.error=Error locating stylesheet {0}. Reason: {1}. | |||||
| ati.attribue-expected.error=Expecting an attribute but received {0}. | |||||
| ati.attribue-unquoted.error=Expecting the value of attribute {0} to be enclosed in quotes. | |||||
| ant.project-banner.notice=Project {0} base directory: {1}. | |||||
| ant.target-parse.notice=Parsing target: {0}. | |||||
| ant.target-dependency.notice=Target dependency: {0} | |||||
| ant.project-unexpected.error=Unexpected error building project. | |||||
| ant.project-parse.error=Could not parse project file. | |||||
| ant.project-build.error=Could not load project from "{0}". | |||||
| ant.no-project-element.error=Project file must be enclosed in project element. | |||||
| ant.unknown-toplevel-element.error=Unknown top-level element {0} at {1}. | |||||
| ant.project-bad-name.error=Invalid project name. | |||||
| ant.project-create-name.error=Could not create a name for this project. | |||||
| ant.projectref-no-name.error=Malformed projectref without a name attribute at {0}. | |||||
| ant.projectref-bad-name.error=Projectref with an invalid name attribute at {0}. | |||||
| ant.projectref-no-location.error=Malformed projectref without a location attribute at {0}. | |||||
| ant.import-no-library.error=Malformed import without a library attribute at {0}. | |||||
| ant.import-malformed.error=Malformed import at {0}. If name or type attribute is specified, both attributes must be specified. | |||||
| ant.target-noname.error=Discovered un-named target at {0}. | |||||
| ant.target-bad-name.error=Target with an invalid name at {0}. | |||||
| ant.target-bad-dependency.error=Discovered empty dependency in target {0} at {1}. | |||||
| ant.malformed.version=Project has an invalid version "{0}". | |||||
| ant.version-missing.error=Project has no version attribute. | |||||
| ant.bad-version.error=Incompatible build file version detected. Expected version {0} but found version {1}. | |||||
| ant.no-project-file.error=Project file does not exist, or is not a file. | |||||
| ant.project-convert.notice=Applying compatibility stylesheet to project file. | |||||
| ant.project-convert.error=Error converting build file. | |||||
| duplicate-project.error=Can not have two projects referenced in a file with the name {0}. | |||||
| duplicate-target.error=Can not have two targets in a file with the name {0}. | |||||
| @@ -1,25 +0,0 @@ | |||||
| /* | |||||
| * 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.components.builder; | |||||
| import org.xml.sax.SAXException; | |||||
| /** | |||||
| * Dummy exception to stop parsing "safely". | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class StopParsingException | |||||
| extends SAXException | |||||
| { | |||||
| public StopParsingException() | |||||
| { | |||||
| super( "" ); | |||||
| } | |||||
| } | |||||
| @@ -1,97 +0,0 @@ | |||||
| /* | |||||
| * 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.components.builder; | |||||
| import java.io.InputStream; | |||||
| import javax.xml.transform.Result; | |||||
| import javax.xml.transform.Source; | |||||
| import javax.xml.transform.Transformer; | |||||
| import javax.xml.transform.TransformerConfigurationException; | |||||
| import javax.xml.transform.TransformerFactory; | |||||
| import javax.xml.transform.sax.SAXResult; | |||||
| import javax.xml.transform.stream.StreamSource; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||||
| import org.apache.myrmidon.interfaces.builder.ProjectException; | |||||
| /** | |||||
| * A Project Builder which performs an XSL transformation on a project. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | |||||
| * @ant.type type="project-builder" name="ant-transform" | |||||
| */ | |||||
| public class TransformingProjectBuilder | |||||
| extends DefaultProjectBuilder | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( TransformingProjectBuilder.class ); | |||||
| private static final String STYLESHEET = "ant1convert.xsl"; | |||||
| private Transformer m_transformer; | |||||
| /** | |||||
| * Builds a project Configuration from a project file, applying the | |||||
| * ant1 conversion stylesheet. | |||||
| * @param systemID the XML system id for the project file | |||||
| * @return the project configuration | |||||
| * @throws ProjectException if a parse error occurs | |||||
| */ | |||||
| protected Configuration parseProject( String systemID ) | |||||
| throws ProjectException | |||||
| { | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( "ant.project-convert.notice" ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| try | |||||
| { | |||||
| // Create a XSLT source for the build file. | |||||
| Source source = new StreamSource( systemID ); | |||||
| // Create a configuration handler for the output. | |||||
| final SAXConfigurationHandler handler = new SAXConfigurationHandler(); | |||||
| Result result = new SAXResult( handler ); | |||||
| // Perform the transformation. | |||||
| getTransformer().transform( source, result ); | |||||
| return handler.getConfiguration(); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| throw new ProjectException( REZ.getString( "ant.project-convert.error" ), | |||||
| e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Lazy load a Transformer with the conversion stylesheet. | |||||
| * @return the initialised Transformer | |||||
| * @throws TransformerConfigurationException | |||||
| */ | |||||
| private Transformer getTransformer() | |||||
| throws TransformerConfigurationException | |||||
| { | |||||
| // Lazy loading of stylesheet source. | |||||
| if( m_transformer == null ) | |||||
| { | |||||
| InputStream stylesheet = | |||||
| this.getClass().getResourceAsStream( STYLESHEET ); | |||||
| StreamSource stylesheetSource = new StreamSource( stylesheet ); | |||||
| TransformerFactory xformFactory = TransformerFactory.newInstance(); | |||||
| m_transformer = xformFactory.newTransformer( stylesheetSource ); | |||||
| } | |||||
| return m_transformer; | |||||
| } | |||||
| } | |||||
| @@ -1,151 +0,0 @@ | |||||
| <?xml version="1.0"?> | |||||
| <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> | |||||
| <xsl:output method="xml" indent="yes"/> | |||||
| <xsl:template match="/project"> | |||||
| <xsl:comment>Converted Project file.</xsl:comment> | |||||
| <xsl:copy> | |||||
| <xsl:attribute name="version">2.0</xsl:attribute> | |||||
| <xsl:apply-templates select="@*[name() != 'version']" mode="copy"/> | |||||
| <xsl:apply-templates/> | |||||
| </xsl:copy> | |||||
| </xsl:template> | |||||
| <!-- For projects with a version attribute, simply copy the entire tree. --> | |||||
| <!-- TODO check for version >= 2.0.0 --> | |||||
| <xsl:template match="/project[@version]"> | |||||
| <xsl:comment>Copied Project file.</xsl:comment> | |||||
| <xsl:copy> | |||||
| <xsl:apply-templates select="@*"/> | |||||
| <xsl:apply-templates mode="copy"/> | |||||
| </xsl:copy> | |||||
| </xsl:template> | |||||
| <!-- Handle simple target nodes --> | |||||
| <xsl:template match="/project/target"> | |||||
| <xsl:copy> | |||||
| <xsl:apply-templates select="@*"/> | |||||
| <xsl:apply-templates/> | |||||
| </xsl:copy> | |||||
| </xsl:template> | |||||
| <!-- Handle target nodes with 'if' --> | |||||
| <xsl:template match="/project/target[@if]"> | |||||
| <xsl:copy> | |||||
| <xsl:apply-templates select="@*[name() != 'if']"/> | |||||
| <!-- Put in the if condition --> | |||||
| <xsl:element name="if"> | |||||
| <xsl:element name="condition"> | |||||
| <xsl:element name="is-set"> | |||||
| <xsl:attribute name="property"> | |||||
| <xsl:value-of select="@if"/> | |||||
| </xsl:attribute> | |||||
| </xsl:element> | |||||
| </xsl:element> | |||||
| <!-- Now add the target content --> | |||||
| <xsl:apply-templates/> | |||||
| </xsl:element> | |||||
| </xsl:copy> | |||||
| </xsl:template> | |||||
| <!-- Handle target nodes with 'unless' --> | |||||
| <xsl:template match="/project/target[@unless]"> | |||||
| <xsl:copy> | |||||
| <xsl:apply-templates select="@*[name() != 'unless']"/> | |||||
| <!-- Put in the unless condition --> | |||||
| <xsl:element name="if"> | |||||
| <xsl:element name="condition"> | |||||
| <xsl:element name="not"> | |||||
| <xsl:element name="is-set"> | |||||
| <xsl:attribute name="property"> | |||||
| <xsl:value-of select="@unless"/> | |||||
| </xsl:attribute> | |||||
| </xsl:element> | |||||
| </xsl:element> | |||||
| </xsl:element> | |||||
| <!-- Now add the target content --> | |||||
| <xsl:apply-templates/> | |||||
| </xsl:element> | |||||
| </xsl:copy> | |||||
| </xsl:template> | |||||
| <!-- Handle target nodes with 'if' and 'unless' --> | |||||
| <xsl:template match="/project/target[@if and @unless]"> | |||||
| <xsl:copy> | |||||
| <xsl:apply-templates select="@*[name()!='if' and name()!='unless']"/> | |||||
| <!-- Put in the 'if' condition --> | |||||
| <xsl:element name="if"> | |||||
| <xsl:element name="condition"> | |||||
| <xsl:element name="is-set"> | |||||
| <xsl:attribute name="property"> | |||||
| <xsl:value-of select="@if"/> | |||||
| </xsl:attribute> | |||||
| </xsl:element> | |||||
| </xsl:element> | |||||
| <!-- Put in the 'unless' condition --> | |||||
| <xsl:element name="if"> | |||||
| <xsl:element name="condition"> | |||||
| <xsl:element name="not"> | |||||
| <xsl:element name="is-set"> | |||||
| <xsl:attribute name="property"> | |||||
| <xsl:value-of select="@unless"/> | |||||
| </xsl:attribute> | |||||
| </xsl:element> | |||||
| </xsl:element> | |||||
| </xsl:element> | |||||
| <!-- Now add the target content --> | |||||
| <xsl:apply-templates/> | |||||
| </xsl:element> | |||||
| </xsl:element> | |||||
| </xsl:copy> | |||||
| </xsl:template> | |||||
| <!-- Handle task nodes, prepending "ant1." --> | |||||
| <xsl:template match="*"> | |||||
| <xsl:element name="ant1.{name()}"> | |||||
| <xsl:apply-templates select="@*"/> | |||||
| <xsl:apply-templates mode="copy"/> | |||||
| </xsl:element> | |||||
| </xsl:template> | |||||
| <!-- Copy all elements in copy-mode --> | |||||
| <xsl:template match="*" mode="copy"> | |||||
| <xsl:copy> | |||||
| <xsl:apply-templates select="@*"/> | |||||
| <xsl:apply-templates mode="copy"/> | |||||
| </xsl:copy> | |||||
| </xsl:template> | |||||
| <!-- Always copy attributes --> | |||||
| <xsl:template match="@*"> | |||||
| <xsl:copy/> | |||||
| </xsl:template> | |||||
| <xsl:template match="@*" mode="copy"> | |||||
| <xsl:copy/> | |||||
| </xsl:template> | |||||
| <!-- Always copy comments --> | |||||
| <xsl:template match="comment()"> | |||||
| <xsl:copy/> | |||||
| </xsl:template> | |||||
| <xsl:template match="comment()" mode="copy"> | |||||
| <xsl:copy/> | |||||
| </xsl:template> | |||||
| </xsl:stylesheet> | |||||
| @@ -1,305 +0,0 @@ | |||||
| /* | |||||
| * 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.components.classloader; | |||||
| import java.io.File; | |||||
| import java.net.MalformedURLException; | |||||
| import java.net.URL; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import java.util.HashSet; | |||||
| import java.util.Map; | |||||
| import java.util.Set; | |||||
| import java.util.jar.JarFile; | |||||
| import java.util.jar.Manifest; | |||||
| import org.apache.aut.nativelib.PathUtil; | |||||
| import org.apache.avalon.excalibur.extension.Extension; | |||||
| import org.apache.avalon.excalibur.extension.OptionalPackage; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.avalon.framework.context.ContextException; | |||||
| import org.apache.avalon.framework.context.Contextualizable; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.interfaces.classloader.ClassLoaderException; | |||||
| import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||||
| import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
| import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||||
| /** | |||||
| * A default implementation of a ClassLoader manager. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultClassLoaderManager | |||||
| extends AbstractLogEnabled | |||||
| implements ClassLoaderManager, Serviceable, Contextualizable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultClassLoaderManager.class ); | |||||
| /** | |||||
| * Map from File/ArrayList to the ClassLoader for that file/files. | |||||
| */ | |||||
| private final Map m_classLoaders = new HashMap(); | |||||
| private ExtensionManager m_extensionManager; | |||||
| private ClassLoader m_commonClassLoader; | |||||
| public DefaultClassLoaderManager() | |||||
| { | |||||
| } | |||||
| public DefaultClassLoaderManager( final ClassLoader commonClassLoader ) | |||||
| { | |||||
| m_commonClassLoader = commonClassLoader; | |||||
| } | |||||
| public void contextualize( final Context context ) throws ContextException | |||||
| { | |||||
| if( null == m_commonClassLoader ) | |||||
| { | |||||
| m_commonClassLoader = (ClassLoader)context.get( "myrmidon.shared.classloader" ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Retrieve relevent services needed to deploy. | |||||
| */ | |||||
| public void service( final ServiceManager serviceManager ) | |||||
| throws ServiceException | |||||
| { | |||||
| m_extensionManager = (ExtensionManager)serviceManager.lookup( ExtensionManager.ROLE ); | |||||
| } | |||||
| /** | |||||
| * Returns the common ClassLoader. This is the parent of all classloaders | |||||
| * built by this ClassLoaderManager. | |||||
| */ | |||||
| public ClassLoader getCommonClassLoader() | |||||
| { | |||||
| return m_commonClassLoader; | |||||
| } | |||||
| /** | |||||
| * Creates a class loader for a Jar file. | |||||
| */ | |||||
| public ClassLoader getClassLoader( final File file ) throws ClassLoaderException | |||||
| { | |||||
| try | |||||
| { | |||||
| final File canonFile = file.getCanonicalFile(); | |||||
| // Check for cached classloader, creating it if required | |||||
| ClassLoader loader = (ClassLoader)m_classLoaders.get( canonFile ); | |||||
| if( loader == null ) | |||||
| { | |||||
| checkFile( canonFile ); | |||||
| final OptionalPackage optionalPackage = toOptionalPackage( canonFile ); | |||||
| loader = buildClassLoader( optionalPackage, new HashSet() ); | |||||
| } | |||||
| return loader; | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "create-classloader-for-file.error", file ); | |||||
| throw new ClassLoaderException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a class loader for a set of Jar files. | |||||
| */ | |||||
| public ClassLoader createClassLoader( final File[] files ) throws ClassLoaderException | |||||
| { | |||||
| try | |||||
| { | |||||
| if( files == null || files.length == 0 ) | |||||
| { | |||||
| return m_commonClassLoader; | |||||
| } | |||||
| // Build a list of optional packages for the files | |||||
| final OptionalPackage[] packages = new OptionalPackage[ files.length ]; | |||||
| for( int i = 0; i < files.length; i++ ) | |||||
| { | |||||
| final File canonFile = files[ i ].getCanonicalFile(); | |||||
| checkFile( canonFile ); | |||||
| packages[ i ] = toOptionalPackage( canonFile ); | |||||
| } | |||||
| // Build the classloaders for the required extensions | |||||
| final ClassLoader[] parentClassLoaders = buildParentClassLoaders( packages, new HashSet() ); | |||||
| // Build the classloader | |||||
| final URL[] urls = buildClasspath( files ); | |||||
| return new MultiParentURLClassLoader( urls, parentClassLoaders ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String fileNames = PathUtil.formatPath( files ); | |||||
| final String message = REZ.getString( "create-classloader-for-files.error", fileNames ); | |||||
| throw new ClassLoaderException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Builds the classloader for an optional package. | |||||
| */ | |||||
| private ClassLoader buildClassLoader( final OptionalPackage pkg, | |||||
| final Set pending ) | |||||
| throws Exception | |||||
| { | |||||
| final File jarFile = pkg.getFile(); | |||||
| // Check for cached classloader | |||||
| ClassLoader classLoader = (ClassLoader)m_classLoaders.get( jarFile ); | |||||
| if( classLoader != null ) | |||||
| { | |||||
| return classLoader; | |||||
| } | |||||
| // Check for cyclic dependency | |||||
| if( pending.contains( jarFile ) ) | |||||
| { | |||||
| final String message = REZ.getString( "dependency-cycle.error", jarFile ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| pending.add( jarFile ); | |||||
| // Build the classloaders for the extensions required by this optional | |||||
| // package | |||||
| final ClassLoader[] parentClassLoaders = | |||||
| buildParentClassLoaders( new OptionalPackage[] { pkg }, pending ); | |||||
| // Create and cache the classloader | |||||
| final URL[] urls = { jarFile.toURL() }; | |||||
| classLoader = new MultiParentURLClassLoader( urls, parentClassLoaders ); | |||||
| m_classLoaders.put( jarFile, classLoader ); | |||||
| pending.remove( jarFile ); | |||||
| return classLoader; | |||||
| } | |||||
| /** | |||||
| * Builds the parent classloaders for a set of optional packages. That is, | |||||
| * the classloaders for all of the extensions required by the given set | |||||
| * of optional packages. | |||||
| */ | |||||
| private ClassLoader[] buildParentClassLoaders( final OptionalPackage[] packages, | |||||
| final Set pending ) | |||||
| throws Exception | |||||
| { | |||||
| final ArrayList classLoaders = new ArrayList(); | |||||
| // Include the common class loader | |||||
| classLoaders.add( m_commonClassLoader ); | |||||
| // Build the classloader for each optional package, filtering out duplicates | |||||
| for( int i = 0; i < packages.length; i++ ) | |||||
| { | |||||
| final OptionalPackage optionalPackage = packages[ i ]; | |||||
| // Locate the dependencies for this jar file | |||||
| final OptionalPackage[] requiredPackages = getOptionalPackagesFor( optionalPackage ); | |||||
| // Build the classloader for the package | |||||
| for( int j = 0; j < requiredPackages.length; j++ ) | |||||
| { | |||||
| final OptionalPackage requiredPackage = requiredPackages[j ]; | |||||
| final ClassLoader classLoader = buildClassLoader( requiredPackage, pending ); | |||||
| if( ! classLoaders.contains( classLoader ) ) | |||||
| { | |||||
| classLoaders.add( classLoader ); | |||||
| } | |||||
| } | |||||
| } | |||||
| return (ClassLoader[])classLoaders.toArray( new ClassLoader[classLoaders.size() ] ); | |||||
| } | |||||
| /** | |||||
| * Assembles a set of files into a URL classpath. | |||||
| */ | |||||
| private URL[] buildClasspath( final File[] files ) | |||||
| throws MalformedURLException | |||||
| { | |||||
| final URL[] urls = new URL[ files.length ]; | |||||
| for( int i = 0; i < files.length; i++ ) | |||||
| { | |||||
| urls[ i ] = files[i ].toURL(); | |||||
| } | |||||
| return urls; | |||||
| } | |||||
| /** | |||||
| * Builds an OptionalPackage for a Jar file. | |||||
| * | |||||
| * @param file the jar. | |||||
| */ | |||||
| private OptionalPackage toOptionalPackage( final File file ) | |||||
| throws Exception | |||||
| { | |||||
| // Determine the extensions required by this file | |||||
| final JarFile jarFile = new JarFile( file ); | |||||
| final Manifest manifest = jarFile.getManifest(); | |||||
| final Extension[] required = Extension.getRequired( manifest ); | |||||
| return new OptionalPackage( file, new Extension[0], required ); | |||||
| } | |||||
| /** | |||||
| * Locates the optional packages required by an optional package. | |||||
| */ | |||||
| private OptionalPackage[] getOptionalPackagesFor( final OptionalPackage pkg ) | |||||
| throws Exception | |||||
| { | |||||
| // Locate the optional packages that provide the required extesions | |||||
| final Extension[] required = pkg.getRequiredExtensions(); | |||||
| final ArrayList packages = new ArrayList(); | |||||
| for( int i = 0; i < required.length; i++ ) | |||||
| { | |||||
| final Extension extension = required[i ]; | |||||
| final OptionalPackage optionalPackage = m_extensionManager.getOptionalPackage( extension ); | |||||
| if( optionalPackage == null ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "unsatisfied.extension.error", | |||||
| pkg.getFile(), | |||||
| extension.getExtensionName(), | |||||
| extension.getSpecificationVersion() ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| packages.add( optionalPackage ); | |||||
| } | |||||
| return (OptionalPackage[])packages.toArray( new OptionalPackage[packages.size() ] ); | |||||
| } | |||||
| /** | |||||
| * Ensures a file exists and is not a directory. | |||||
| */ | |||||
| private void checkFile( final File file ) | |||||
| throws DeploymentException | |||||
| { | |||||
| if( !file.exists() ) | |||||
| { | |||||
| final String message = REZ.getString( "no-file.error", file ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| if( file.isDirectory() ) | |||||
| { | |||||
| final String message = REZ.getString( "file-is-dir.error", file ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,141 +0,0 @@ | |||||
| /* | |||||
| * 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.components.classloader; | |||||
| import java.io.IOException; | |||||
| import java.net.URL; | |||||
| import java.net.URLClassLoader; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Collections; | |||||
| import java.util.Enumeration; | |||||
| import java.util.List; | |||||
| import java.util.Set; | |||||
| import java.util.HashSet; | |||||
| /** | |||||
| * A URLClassLoader with more than one parent. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class MultiParentURLClassLoader | |||||
| extends URLClassLoader | |||||
| { | |||||
| private final ClassLoader[] m_parents; | |||||
| /** | |||||
| * Constructs a new URLClassLoader for the given URLs. | |||||
| * | |||||
| * @param urls the URLs from which to load classes and resources | |||||
| * @param parents the parent class loaderer for delegation | |||||
| */ | |||||
| public MultiParentURLClassLoader( final URL[] urls, final ClassLoader[] parents ) | |||||
| { | |||||
| super( urls ); | |||||
| m_parents = parents; | |||||
| } | |||||
| /** | |||||
| * Finds a class. | |||||
| * | |||||
| * @param name the name of the class | |||||
| * @return the resulting class | |||||
| * @exception ClassNotFoundException if the class could not be found | |||||
| */ | |||||
| protected Class findClass( final String name ) | |||||
| throws ClassNotFoundException | |||||
| { | |||||
| // Try the parent classloaders first | |||||
| for( int i = 0; i < m_parents.length; i++ ) | |||||
| { | |||||
| try | |||||
| { | |||||
| final ClassLoader parent = m_parents[ i ]; | |||||
| return parent.loadClass( name ); | |||||
| } | |||||
| catch( ClassNotFoundException e ) | |||||
| { | |||||
| // Ignore - continue to the next ClassLoader | |||||
| } | |||||
| } | |||||
| // Now this classloader | |||||
| return super.findClass( name ); | |||||
| } | |||||
| /** | |||||
| * Finds a resource. | |||||
| * | |||||
| * @param name the name of the resource | |||||
| * @return a <code>URL</code> for the resource, or <code>null</code> | |||||
| * if the resource could not be found. | |||||
| */ | |||||
| public URL findResource( final String name ) | |||||
| { | |||||
| // Try the parent classloaders first | |||||
| for( int i = 0; i < m_parents.length; i++ ) | |||||
| { | |||||
| final ClassLoader parent = m_parents[ i ]; | |||||
| final URL resource = parent.getResource( name ); | |||||
| if( resource != null ) | |||||
| { | |||||
| return resource; | |||||
| } | |||||
| } | |||||
| // Now this classloader | |||||
| return super.findResource( name ); | |||||
| } | |||||
| /** | |||||
| * Returns an Enumeration of URLs representing all of the resources | |||||
| * having the specified name. | |||||
| * | |||||
| * @param name the resource name | |||||
| * @throws IOException if an I/O exception occurs | |||||
| * @return an <code>Enumeration</code> of <code>URL</code>s | |||||
| */ | |||||
| public Enumeration findResources( final String name ) throws IOException | |||||
| { | |||||
| // Need to filter out duplicate resources | |||||
| final ArrayList urls = new ArrayList(); | |||||
| final Set urlSet = new HashSet(); | |||||
| // Gather the resources from the parent classloaders | |||||
| for( int i = 0; i < m_parents.length; i++ ) | |||||
| { | |||||
| final ClassLoader parent = m_parents[ i ]; | |||||
| final Enumeration enum = parent.getResources( name ); | |||||
| addUrls( enum, urls, urlSet ); | |||||
| } | |||||
| // Gather the resources from this classloader | |||||
| addUrls( super.findResources( name ), urls, urlSet ); | |||||
| return Collections.enumeration( urls ); | |||||
| } | |||||
| /** | |||||
| * Adds those URLs not already present. | |||||
| */ | |||||
| private void addUrls( final Enumeration enum, | |||||
| final List urls, | |||||
| final Set urlSet ) | |||||
| { | |||||
| while( enum.hasMoreElements() ) | |||||
| { | |||||
| final URL url = (URL)enum.nextElement(); | |||||
| final String urlStr = url.toExternalForm(); | |||||
| if( !urlSet.contains( urlStr ) ) | |||||
| { | |||||
| urls.add( url ); | |||||
| urlSet.add( urlStr ); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,5 +0,0 @@ | |||||
| create-classloader-for-file.error=Could not create a ClassLoader for "{0}". | |||||
| create-classloader-for-files.error=Could not create a ClassLoader for {0}. | |||||
| unsatisfied.extension.error=Library "{0}" requires unknown extension "{1}" ( version {2}). | |||||
| no-file.error=Could not find library "{0}". | |||||
| file-is-dir.error=Library "{0}" is a directory. | |||||
| @@ -1,567 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| import java.lang.reflect.InvocationTargetException; | |||||
| import java.lang.reflect.Method; | |||||
| import java.util.ArrayList; | |||||
| import org.apache.aut.converter.Converter; | |||||
| import org.apache.aut.converter.ConverterException; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.Configurable; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.logger.LogEnabled; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.interfaces.configurer.Configurer; | |||||
| /** | |||||
| * Class used to configure tasks. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @ant.type type="configurer" name="classic" | |||||
| */ | |||||
| public class ClassicConfigurer | |||||
| extends AbstractLogEnabled | |||||
| implements Configurer, Serviceable, LogEnabled | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultConfigurer.class ); | |||||
| ///Compile time constant to turn on extreme debugging | |||||
| private static final boolean DEBUG = false; | |||||
| ///Converter to use for converting between values | |||||
| private Converter m_converter; | |||||
| public void service( final ServiceManager serviceManager ) | |||||
| throws ServiceException | |||||
| { | |||||
| m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||||
| } | |||||
| /** | |||||
| * Configure an object based on a configuration in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * The implementation of this method should only use the methods | |||||
| * specified by the supplied class. It is an error for the specified | |||||
| * class not to be a base class or interface compatible with specified | |||||
| * object. | |||||
| * | |||||
| * @param object the object | |||||
| * @param clazz the Class object to use during configuration | |||||
| * @param configuration the configuration | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| public void configureElement( Object object, | |||||
| Class clazz, | |||||
| Configuration configuration, | |||||
| TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| throw new UnsupportedOperationException(); | |||||
| } | |||||
| /** | |||||
| * Configure named attribute of object in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * The implementation of this method should only use the methods | |||||
| * specified by the supplied class. It is an error for the specified | |||||
| * class not to be a base class or interface compatible with specified | |||||
| * object. | |||||
| * | |||||
| * @param object the object | |||||
| * @param clazz the Class object to use during configuration | |||||
| * @param name the attribute name | |||||
| * @param value the attribute value | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| public void configureAttribute( Object object, | |||||
| Class clazz, | |||||
| String name, | |||||
| String value, | |||||
| TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| throw new UnsupportedOperationException(); | |||||
| } | |||||
| /** | |||||
| * Configure a task based on a configuration in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * This one does it by first checking if object implements Configurable | |||||
| * and if it does will pass the task the configuration - else it will use | |||||
| * mapping rules to map configuration to types | |||||
| * | |||||
| * @param object the object | |||||
| * @param configuration the configuration | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| public void configureElement( final Object object, | |||||
| final Configuration configuration, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = REZ.getString( "configuring-object.notice", object ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| if( object instanceof Configurable ) | |||||
| { | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = REZ.getString( "configurable.notice" ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| final Configurable configurable = (Configurable)object; | |||||
| configurable.configure( configuration ); | |||||
| } | |||||
| else | |||||
| { | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = REZ.getString( "reflection.notice" ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| final String[] attributes = configuration.getAttributeNames(); | |||||
| for( int i = 0; i < attributes.length; i++ ) | |||||
| { | |||||
| final String name = attributes[ i ]; | |||||
| final String value = configuration.getAttribute( name ); | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = REZ.getString( "configure-attribute.notice", | |||||
| name, value ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| doConfigureAttribute( object, name, value, context ); | |||||
| } | |||||
| final Configuration[] children = configuration.getChildren(); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | |||||
| final Configuration child = children[ i ]; | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "configure-subelement.notice", child.getName() ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| doConfigureElement( object, child, context ); | |||||
| } | |||||
| final String content = configuration.getValue( null ); | |||||
| if( null != content ) | |||||
| { | |||||
| if( !content.trim().equals( "" ) ) | |||||
| { | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "configure-content.notice", content ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| configureContent( object, content, context ); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Configure named attribute of object in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * @param object the object | |||||
| * @param name the attribute name | |||||
| * @param value the attribute value | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| public void configureAttribute( final Object object, | |||||
| final String name, | |||||
| final String value, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| doConfigureAttribute( object, name, value, context ); | |||||
| } | |||||
| /** | |||||
| * Try to configure content of an object. | |||||
| * | |||||
| * @param object the object | |||||
| * @param content the content value to be set | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| private void configureContent( final Object object, | |||||
| final String content, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| setValue( object, "addContent", content, context ); | |||||
| } | |||||
| private void doConfigureAttribute( final Object object, | |||||
| final String name, | |||||
| final String value, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final String methodName = getMethodNameFor( name ); | |||||
| setValue( object, methodName, value, context ); | |||||
| } | |||||
| private void setValue( final Object object, | |||||
| final String methodName, | |||||
| final String value, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| // OMFG the rest of this is soooooooooooooooooooooooooooooooo | |||||
| // slow. Need to cache results per class etc. | |||||
| final Class clazz = object.getClass(); | |||||
| final Method[] methods = getMethodsFor( clazz, methodName ); | |||||
| if( 0 == methods.length ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "no-attribute-method.error", methodName ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| setValue( object, value, context, methods ); | |||||
| } | |||||
| private void setValue( final Object object, | |||||
| final String value, | |||||
| final TaskContext context, | |||||
| final Method[] methods ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| { | |||||
| final Object objectValue = context.resolveValue( value ); | |||||
| setValue( object, objectValue, methods, context ); | |||||
| } | |||||
| catch( final TaskException te ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "bad-property-resolve.error", value ); | |||||
| throw new ConfigurationException( message, te ); | |||||
| } | |||||
| } | |||||
| private void setValue( final Object object, | |||||
| Object value, | |||||
| final Method[] methods, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final Class sourceClass = value.getClass(); | |||||
| final String source = sourceClass.getName(); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| { | |||||
| if( setValue( object, value, methods[ i ], context ) ) | |||||
| { | |||||
| return; | |||||
| } | |||||
| } | |||||
| final String message = | |||||
| REZ.getString( "no-can-convert.error", methods[ 0 ].getName(), source ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| private boolean setValue( final Object object, | |||||
| final Object originalValue, | |||||
| final Method method, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| Class parameterType = method.getParameterTypes()[ 0 ]; | |||||
| if( parameterType.isPrimitive() ) | |||||
| { | |||||
| parameterType = getComplexTypeFor( parameterType ); | |||||
| } | |||||
| Object value = originalValue; | |||||
| try | |||||
| { | |||||
| value = m_converter.convert( parameterType, value, context ); | |||||
| } | |||||
| catch( final ConverterException ce ) | |||||
| { | |||||
| if( DEBUG ) | |||||
| { | |||||
| final String message = REZ.getString( "no-converter.error" ); | |||||
| getLogger().debug( message, ce ); | |||||
| } | |||||
| throw new ConfigurationException( ce.getMessage(), ce ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "bad-convert-for-attribute.error", method.getName() ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | |||||
| if( null == value ) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| try | |||||
| { | |||||
| method.invoke( object, new Object[]{value} ); | |||||
| } | |||||
| catch( final IllegalAccessException iae ) | |||||
| { | |||||
| //should never happen .... | |||||
| final String message = REZ.getString( "illegal-access.error" ); | |||||
| throw new ConfigurationException( message, iae ); | |||||
| } | |||||
| catch( final InvocationTargetException ite ) | |||||
| { | |||||
| final String message = REZ.getString( "invoke-target.error", method.getName() ); | |||||
| throw new ConfigurationException( message, ite ); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| private Class getComplexTypeFor( final Class clazz ) | |||||
| { | |||||
| if( String.class == clazz ) | |||||
| { | |||||
| return String.class; | |||||
| } | |||||
| else if( Integer.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Integer.class; | |||||
| } | |||||
| else if( Long.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Long.class; | |||||
| } | |||||
| else if( Short.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Short.class; | |||||
| } | |||||
| else if( Byte.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Byte.class; | |||||
| } | |||||
| else if( Boolean.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Boolean.class; | |||||
| } | |||||
| else if( Float.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Float.class; | |||||
| } | |||||
| else if( Double.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Double.class; | |||||
| } | |||||
| else | |||||
| { | |||||
| final String message = REZ.getString( "no-complex-type.error", clazz.getName() ); | |||||
| throw new IllegalArgumentException( message ); | |||||
| } | |||||
| } | |||||
| private Method[] getMethodsFor( final Class clazz, final String methodName ) | |||||
| { | |||||
| final Method[] methods = clazz.getMethods(); | |||||
| final ArrayList matches = new ArrayList(); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| { | |||||
| final Method method = methods[ i ]; | |||||
| if( methodName.equals( method.getName() ) && | |||||
| Method.PUBLIC == ( method.getModifiers() & Method.PUBLIC ) ) | |||||
| { | |||||
| if( method.getReturnType().equals( Void.TYPE ) ) | |||||
| { | |||||
| final Class[] parameters = method.getParameterTypes(); | |||||
| if( 1 == parameters.length ) | |||||
| { | |||||
| matches.add( method ); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return (Method[])matches.toArray( new Method[ 0 ] ); | |||||
| } | |||||
| private Method[] getCreateMethodsFor( final Class clazz, final String methodName ) | |||||
| { | |||||
| final Method[] methods = clazz.getMethods(); | |||||
| final ArrayList matches = new ArrayList(); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| { | |||||
| final Method method = methods[ i ]; | |||||
| if( methodName.equals( method.getName() ) && | |||||
| Method.PUBLIC == ( method.getModifiers() & Method.PUBLIC ) ) | |||||
| { | |||||
| final Class returnType = method.getReturnType(); | |||||
| if( !returnType.equals( Void.TYPE ) && | |||||
| !returnType.isPrimitive() ) | |||||
| { | |||||
| final Class[] parameters = method.getParameterTypes(); | |||||
| if( 0 == parameters.length ) | |||||
| { | |||||
| matches.add( method ); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return (Method[])matches.toArray( new Method[ 0 ] ); | |||||
| } | |||||
| private String getMethodNameFor( final String attribute ) | |||||
| { | |||||
| return "set" + getJavaNameFor( attribute.toLowerCase() ); | |||||
| } | |||||
| private String getJavaNameFor( final String name ) | |||||
| { | |||||
| final StringBuffer sb = new StringBuffer(); | |||||
| int index = name.indexOf( '-' ); | |||||
| int last = 0; | |||||
| while( -1 != index ) | |||||
| { | |||||
| final String word = name.substring( last, index ).toLowerCase(); | |||||
| sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); | |||||
| sb.append( word.substring( 1, word.length() ) ); | |||||
| last = index + 1; | |||||
| index = name.indexOf( '-', last ); | |||||
| } | |||||
| index = name.length(); | |||||
| final String word = name.substring( last, index ).toLowerCase(); | |||||
| sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); | |||||
| sb.append( word.substring( 1, word.length() ) ); | |||||
| return sb.toString(); | |||||
| } | |||||
| private void doConfigureElement( final Object object, | |||||
| final Configuration configuration, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final String name = configuration.getName(); | |||||
| final String javaName = getJavaNameFor( name ); | |||||
| // OMFG the rest of this is soooooooooooooooooooooooooooooooo | |||||
| // slow. Need to cache results per class etc. | |||||
| final Class clazz = object.getClass(); | |||||
| Method[] methods = getMethodsFor( clazz, "add" + javaName ); | |||||
| if( 0 != methods.length ) | |||||
| { | |||||
| //guess it is first method ???? | |||||
| addElement( object, methods[ 0 ], configuration, context ); | |||||
| } | |||||
| else | |||||
| { | |||||
| methods = getCreateMethodsFor( clazz, "create" + javaName ); | |||||
| if( 0 == methods.length ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "no-element-method.error", javaName ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| //guess it is first method ???? | |||||
| createElement( object, methods[ 0 ], configuration, context ); | |||||
| } | |||||
| } | |||||
| private void createElement( final Object object, | |||||
| final Method method, | |||||
| final Configuration configuration, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| { | |||||
| final Object created = method.invoke( object, new Object[ 0 ] ); | |||||
| doConfigureElement( created, configuration, context ); | |||||
| } | |||||
| catch( final ConfigurationException ce ) | |||||
| { | |||||
| throw ce; | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "subelement-create.error" ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | |||||
| } | |||||
| private void addElement( final Object object, | |||||
| final Method method, | |||||
| final Configuration configuration, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| { | |||||
| final Class clazz = method.getParameterTypes()[ 0 ]; | |||||
| final Object created = clazz.newInstance(); | |||||
| doConfigureElement( created, configuration, context ); | |||||
| method.invoke( object, new Object[]{created} ); | |||||
| } | |||||
| catch( final ConfigurationException ce ) | |||||
| { | |||||
| throw ce; | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "subelement-create.error" ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,57 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| /** | |||||
| * A default configuration state implementation. Keeps track of which | |||||
| * of the object's properties have been set. | |||||
| * | |||||
| * @author Adam Murdoch | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class ConfigurationState | |||||
| { | |||||
| private final int[] m_propertyCount; | |||||
| private final ObjectConfigurer m_configurer; | |||||
| private final Object m_object; | |||||
| public ConfigurationState( final ObjectConfigurer configurer, | |||||
| final Object object, | |||||
| final int propertyCount ) | |||||
| { | |||||
| m_configurer = configurer; | |||||
| m_object = object; | |||||
| m_propertyCount = new int[ propertyCount ]; | |||||
| } | |||||
| /** | |||||
| * Returns the configurer being used to configure the object. | |||||
| */ | |||||
| public ObjectConfigurer getConfigurer() | |||||
| { | |||||
| return m_configurer; | |||||
| } | |||||
| /** Returns the object being configured. */ | |||||
| public Object getObject() | |||||
| { | |||||
| return m_object; | |||||
| } | |||||
| /** Returns a property count. */ | |||||
| public int getPropertyCount( final int index ) | |||||
| { | |||||
| return m_propertyCount[ index ]; | |||||
| } | |||||
| /** Increments a property count. */ | |||||
| public void incPropertyCount( final int index ) | |||||
| { | |||||
| m_propertyCount[ index ]++; | |||||
| } | |||||
| } | |||||
| @@ -1,645 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| import org.apache.aut.converter.Converter; | |||||
| import org.apache.aut.converter.ConverterException; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.Configurable; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.logger.LogEnabled; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| import org.apache.myrmidon.framework.DataType; | |||||
| import org.apache.myrmidon.interfaces.configurer.Configurer; | |||||
| import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
| import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| /** | |||||
| * Class used to configure tasks. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * @ant.type type="configurer" name="default" | |||||
| */ | |||||
| public class DefaultConfigurer | |||||
| extends AbstractLogEnabled | |||||
| implements Configurer, Serviceable, LogEnabled | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultConfigurer.class ); | |||||
| ///Converter to use for converting between values | |||||
| private Converter m_converter; | |||||
| //TypeManager to use to create types in typed adders | |||||
| private TypeManager m_typeManager; | |||||
| //RoleManager to use to map from type names -> role shorthand | |||||
| private RoleManager m_roleManager; | |||||
| ///Cached object configurers. This is a map from Class to the | |||||
| ///ObjectConfigurer for that class. | |||||
| private Map m_configurerCache = new HashMap(); | |||||
| public void service( final ServiceManager serviceManager ) | |||||
| throws ServiceException | |||||
| { | |||||
| m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||||
| m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||||
| m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||||
| } | |||||
| /** | |||||
| * Configure a task based on a configuration in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * This one does it by first checking if object implements Configurable | |||||
| * and if it does will pass the task the configuration - else it will use | |||||
| * mapping rules to map configuration to types | |||||
| * | |||||
| * @param object the object | |||||
| * @param configuration the configuration | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| public void configureElement( final Object object, | |||||
| final Configuration configuration, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| configureElement( object, object.getClass(), configuration, context ); | |||||
| } | |||||
| public void configureElement( final Object object, | |||||
| final Class clazz, | |||||
| final Configuration configuration, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| try | |||||
| { | |||||
| // Configure the object | |||||
| configureObject( object, clazz, configuration, context ); | |||||
| } | |||||
| catch( final ReportableConfigurationException e ) | |||||
| { | |||||
| // Already have a reasonable error message - so rethrow | |||||
| throw e.getCause(); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| // Wrap all other errors with general purpose error message | |||||
| final String message = REZ.getString( "bad-configure-element.error", | |||||
| configuration.getName() ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Does the work of configuring an object. | |||||
| * | |||||
| * @throws ReportableConfigurationException On error. This exception | |||||
| * indicates that the error has been wrapped with an appropriate | |||||
| * error message. | |||||
| * @throws Exception On error | |||||
| */ | |||||
| private void configureObject( final Object object, | |||||
| final Class clazz, | |||||
| final Configuration configuration, | |||||
| final TaskContext context ) | |||||
| throws Exception | |||||
| { | |||||
| if( object instanceof Configurable ) | |||||
| { | |||||
| // Let the object configure itself | |||||
| ( (Configurable)object ).configure( configuration ); | |||||
| } | |||||
| else | |||||
| { | |||||
| // Start configuration of the object | |||||
| final String elemName = configuration.getName(); | |||||
| final ObjectConfigurer configurer = getConfigurer( clazz ); | |||||
| final ConfigurationState state = configurer.startConfiguration( object ); | |||||
| // Set each of the attributes | |||||
| final String[] attributes = configuration.getAttributeNames(); | |||||
| for( int i = 0; i < attributes.length; i++ ) | |||||
| { | |||||
| final String name = attributes[ i ]; | |||||
| try | |||||
| { | |||||
| // Set the attribute | |||||
| final String value = configuration.getAttribute( name ); | |||||
| setAttribute( state, name, value, context ); | |||||
| } | |||||
| catch( final NoSuchPropertyException nspe ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "no-such-attribute.error", elemName, name ); | |||||
| throw new ReportableConfigurationException( message ); | |||||
| } | |||||
| catch( final Exception ce ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "bad-set-attribute.error", elemName, name ); | |||||
| throw new ReportableConfigurationException( message, ce ); | |||||
| } | |||||
| } | |||||
| // Set the text content | |||||
| final String content = configuration.getValue( null ); | |||||
| if( null != content && content.length() > 0 ) | |||||
| { | |||||
| try | |||||
| { | |||||
| // Set the content | |||||
| setContent( state, content, context ); | |||||
| } | |||||
| catch( final NoSuchPropertyException nspe ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "no-content.error", elemName ); | |||||
| throw new ReportableConfigurationException( message ); | |||||
| } | |||||
| catch( final Exception ce ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "bad-set-content.error", elemName ); | |||||
| throw new ReportableConfigurationException( message, ce ); | |||||
| } | |||||
| } | |||||
| // Create and configure each of the child elements | |||||
| final Configuration[] children = configuration.getChildren(); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | |||||
| final Configuration childConfig = children[ i ]; | |||||
| final String name = childConfig.getName(); | |||||
| try | |||||
| { | |||||
| configureElement( state, childConfig, context ); | |||||
| } | |||||
| catch( final NoSuchPropertyException nspe ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "no-such-element.error", elemName, name ); | |||||
| throw new ReportableConfigurationException( message ); | |||||
| } | |||||
| catch( final ReportableConfigurationException ce ) | |||||
| { | |||||
| throw ce; | |||||
| } | |||||
| catch( final Exception ce ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "bad-configure-element.error", name ); | |||||
| throw new ReportableConfigurationException( message, ce ); | |||||
| } | |||||
| } | |||||
| // Finish configuring the object | |||||
| configurer.finishConfiguration( state ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Configure named attribute of object in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * @param object the object | |||||
| * @param name the attribute name | |||||
| * @param value the attribute value | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| public void configureAttribute( final Object object, | |||||
| final String name, | |||||
| final String value, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| configureAttribute( object, object.getClass(), name, value, context ); | |||||
| } | |||||
| /** | |||||
| * Configure named attribute of object in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * @param object the object | |||||
| * @param name the attribute name | |||||
| * @param value the attribute value | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| public void configureAttribute( final Object object, | |||||
| final Class clazz, | |||||
| final String name, | |||||
| final String value, | |||||
| final TaskContext context ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| // Locate the configurer for this object | |||||
| final ObjectConfigurer configurer = getConfigurer( clazz ); | |||||
| // TODO - this ain't right, the validation is going to be screwed up | |||||
| final ConfigurationState state = configurer.startConfiguration( object ); | |||||
| // Set the attribute value | |||||
| try | |||||
| { | |||||
| setAttribute( state, name, value, context ); | |||||
| } | |||||
| catch( final Exception ce ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "bad-set-class-attribute.error", | |||||
| name, | |||||
| object.getClass().getName() ); | |||||
| throw new ConfigurationException( message, ce ); | |||||
| } | |||||
| // Finish up | |||||
| configurer.finishConfiguration( state ); | |||||
| } | |||||
| /** | |||||
| * Sets the text content for the element. | |||||
| */ | |||||
| private void setContent( final ConfigurationState state, | |||||
| final String content, | |||||
| final TaskContext context ) | |||||
| throws Exception | |||||
| { | |||||
| // Locate the content configurer | |||||
| final PropertyConfigurer contentConfigurer = state.getConfigurer().getContentConfigurer(); | |||||
| if( contentConfigurer == null ) | |||||
| { | |||||
| throw new NoSuchPropertyException(); | |||||
| } | |||||
| // Set the content | |||||
| setValue( contentConfigurer, state, content, context ); | |||||
| } | |||||
| /** | |||||
| * Configures a property from a nested element. | |||||
| */ | |||||
| private void configureElement( final ConfigurationState state, | |||||
| final Configuration element, | |||||
| final TaskContext context ) | |||||
| throws Exception | |||||
| { | |||||
| final String elementName = element.getName(); | |||||
| if( elementName.toLowerCase().endsWith( "-ref" ) ) | |||||
| { | |||||
| // A reference | |||||
| configureReference( state, element, context ); | |||||
| } | |||||
| else | |||||
| { | |||||
| // An inline object | |||||
| configureInline( state, element, context ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Configure a property from an inline object. | |||||
| */ | |||||
| private void configureInline( final ConfigurationState state, | |||||
| final Configuration element, | |||||
| final TaskContext context ) | |||||
| throws Exception | |||||
| { | |||||
| final String name = element.getName(); | |||||
| // Locate the configurer for the child element | |||||
| final PropertyConfigurer childConfigurer = | |||||
| getConfigurerFromName( state.getConfigurer(), name, true, true ); | |||||
| // Create & configure the child element | |||||
| final Object child = | |||||
| setupChild( state, element, context, childConfigurer ); | |||||
| // Set the child element | |||||
| childConfigurer.addValue( state, child ); | |||||
| } | |||||
| /** | |||||
| * Configures a property from a reference. | |||||
| */ | |||||
| private void configureReference( final ConfigurationState state, | |||||
| final Configuration element, | |||||
| final TaskContext context ) | |||||
| throws Exception | |||||
| { | |||||
| // Extract the id | |||||
| final String id = element.getAttribute( "id" ); | |||||
| if( 1 != element.getAttributeNames().length || | |||||
| 0 != element.getChildren().length ) | |||||
| { | |||||
| final String message = REZ.getString( "extra-config-for-ref.error" ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| // Set the property | |||||
| final String name = element.getName(); | |||||
| setReference( state, name, id, context, true ); | |||||
| } | |||||
| /** | |||||
| * Sets a property using a reference. | |||||
| */ | |||||
| private void setReference( final ConfigurationState state, | |||||
| final String refName, | |||||
| final String unresolvedId, | |||||
| final TaskContext context, | |||||
| final boolean isAdder ) | |||||
| throws Exception | |||||
| { | |||||
| // Adjust the name | |||||
| final String name = refName.substring( 0, refName.length() - 4 ); | |||||
| // Locate the configurer for the property | |||||
| final PropertyConfigurer configurer = | |||||
| getConfigurerFromName( state.getConfigurer(), name, false, isAdder ); | |||||
| // Resolve any props in the id | |||||
| String id = context.resolveValue( unresolvedId ).toString(); | |||||
| // Locate the referenced object | |||||
| Object ref = context.getProperty( id ); | |||||
| if( null == ref ) | |||||
| { | |||||
| final String message = REZ.getString( "unknown-reference.error", id ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| // Convert the object, if necessary | |||||
| final Class type = configurer.getType(); | |||||
| if( !type.isInstance( ref ) ) | |||||
| { | |||||
| try | |||||
| { | |||||
| ref = m_converter.convert( type, ref, context ); | |||||
| } | |||||
| catch( ConverterException e ) | |||||
| { | |||||
| final String message = REZ.getString( "mismatch-ref-types.error", id, name ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | |||||
| } | |||||
| // Set the child element | |||||
| configurer.addValue( state, ref ); | |||||
| } | |||||
| /** | |||||
| * Sets an attribute value. | |||||
| */ | |||||
| private void setAttribute( final ConfigurationState state, | |||||
| final String name, | |||||
| final String value, | |||||
| final TaskContext context ) | |||||
| throws Exception | |||||
| { | |||||
| // Set the value | |||||
| final PropertyConfigurer property = | |||||
| getConfigurerFromName( state.getConfigurer(), name, false, false ); | |||||
| setValue( property, state, value, context ); | |||||
| } | |||||
| /** | |||||
| * Sets an attribute value, or an element's text content. | |||||
| */ | |||||
| private void setValue( final PropertyConfigurer setter, | |||||
| final ConfigurationState state, | |||||
| final String value, | |||||
| final TaskContext context ) | |||||
| throws Exception | |||||
| { | |||||
| // Resolve property references in the attribute value | |||||
| Object objValue = context.resolveValue( value ); | |||||
| // Convert the value to the appropriate type | |||||
| final Class type = setter.getType(); | |||||
| if( !type.isInstance( objValue ) ) | |||||
| { | |||||
| objValue = m_converter.convert( type, objValue, context ); | |||||
| } | |||||
| // Set the value | |||||
| setter.addValue( state, objValue ); | |||||
| } | |||||
| /** | |||||
| * Locates the configurer for a particular class. | |||||
| */ | |||||
| private ObjectConfigurer getConfigurer( final Class clazz ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| ObjectConfigurer configurer = | |||||
| (ObjectConfigurer)m_configurerCache.get( clazz ); | |||||
| if( null == configurer ) | |||||
| { | |||||
| configurer = DefaultObjectConfigurer.getConfigurer( clazz ); | |||||
| m_configurerCache.put( clazz, configurer ); | |||||
| } | |||||
| return configurer; | |||||
| } | |||||
| /** | |||||
| * Creates and configures an inline object. | |||||
| */ | |||||
| private Object setupChild( final ConfigurationState state, | |||||
| final Configuration element, | |||||
| final TaskContext context, | |||||
| final PropertyConfigurer childConfigurer ) | |||||
| throws Exception | |||||
| { | |||||
| final String name = element.getName(); | |||||
| final Class type = childConfigurer.getType(); | |||||
| if( Configuration.class == type ) | |||||
| { | |||||
| //special case where you have add...(Configuration) | |||||
| return element; | |||||
| } | |||||
| // Create an instance | |||||
| Object child = null; | |||||
| if( childConfigurer == state.getConfigurer().getTypedProperty() ) | |||||
| { | |||||
| // Typed property | |||||
| child = createTypedObject( name, type ); | |||||
| } | |||||
| else | |||||
| { | |||||
| // Named property | |||||
| child = createNamedObject( type ); | |||||
| } | |||||
| // Configure the object | |||||
| final Object object = child; | |||||
| configureObject( object, object.getClass(), element, context ); | |||||
| // Convert the object, if necessary | |||||
| if( !type.isInstance( child ) ) | |||||
| { | |||||
| child = m_converter.convert( type, child, context ); | |||||
| } | |||||
| return child; | |||||
| } | |||||
| /** | |||||
| * Determines the property configurer to use for a particular element | |||||
| * or attribute. If the supplied name matches a property of the | |||||
| * class being configured, that property configurer is returned. If | |||||
| * the supplied name matches the role shorthand for the class' typed | |||||
| * property, then the typed property configurer is used. | |||||
| * | |||||
| * @param configurer The configurer for the class being configured. | |||||
| * @param name The attribute/element name. | |||||
| */ | |||||
| private PropertyConfigurer getConfigurerFromName( final ObjectConfigurer configurer, | |||||
| final String name, | |||||
| boolean ignoreRoleName, | |||||
| final boolean isAdder ) | |||||
| throws Exception | |||||
| { | |||||
| // Try a named property | |||||
| if( !isAdder ) | |||||
| { | |||||
| PropertyConfigurer propertyConfigurer = configurer.getSetter( name ); | |||||
| if( propertyConfigurer != null ) | |||||
| { | |||||
| return propertyConfigurer; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| PropertyConfigurer propertyConfigurer = configurer.getAdder( name ); | |||||
| if( propertyConfigurer != null ) | |||||
| { | |||||
| return propertyConfigurer; | |||||
| } | |||||
| // Try a typed property | |||||
| propertyConfigurer = configurer.getTypedProperty(); | |||||
| if( propertyConfigurer != null ) | |||||
| { | |||||
| if( ignoreRoleName ) | |||||
| { | |||||
| return propertyConfigurer; | |||||
| } | |||||
| else | |||||
| { | |||||
| // Check the role name | |||||
| final RoleInfo roleInfo = | |||||
| m_roleManager.getRoleByType( propertyConfigurer.getType() ); | |||||
| if( roleInfo != null && name.equalsIgnoreCase( roleInfo.getShorthand() ) ) | |||||
| { | |||||
| return propertyConfigurer; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // Unknown prop | |||||
| throw new NoSuchPropertyException(); | |||||
| } | |||||
| /** | |||||
| * Creates an instance for a named property. | |||||
| */ | |||||
| private Object createNamedObject( final Class type ) | |||||
| throws Exception | |||||
| { | |||||
| // Map the expected type to a role. If found, instantiate the default | |||||
| // type for that role | |||||
| final RoleInfo roleInfo = m_roleManager.getRoleByType( type ); | |||||
| if( roleInfo != null ) | |||||
| { | |||||
| final String typeName = roleInfo.getDefaultType(); | |||||
| if( typeName != null ) | |||||
| { | |||||
| // Create the instance | |||||
| final TypeFactory factory = m_typeManager.getFactory( roleInfo.getName() ); | |||||
| return factory.create( typeName ); | |||||
| } | |||||
| } | |||||
| if( type.isInterface() ) | |||||
| { | |||||
| // An interface - don't know how to instantiate it | |||||
| final String message = REZ.getString( "instantiate-interface.error", type.getName() ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| // Use the no-args constructor | |||||
| return createObject( type ); | |||||
| } | |||||
| /** | |||||
| * Creates an instance of the typed property. | |||||
| */ | |||||
| private Object createTypedObject( final String name, | |||||
| final Class type ) | |||||
| throws Exception | |||||
| { | |||||
| // Map the expected type to a role. If found, attempt to create | |||||
| // an instance | |||||
| final RoleInfo roleInfo = m_roleManager.getRoleByType( type ); | |||||
| if( roleInfo != null ) | |||||
| { | |||||
| final TypeFactory factory = m_typeManager.getFactory( roleInfo.getName() ); | |||||
| if( factory.canCreate( name ) ) | |||||
| { | |||||
| return factory.create( name ); | |||||
| } | |||||
| } | |||||
| // Use the generic 'data-type' role. | |||||
| final TypeFactory factory = m_typeManager.getFactory( DataType.ROLE ); | |||||
| if( !factory.canCreate( name ) ) | |||||
| { | |||||
| throw new NoSuchPropertyException(); | |||||
| } | |||||
| return factory.create( name ); | |||||
| } | |||||
| /** | |||||
| * Utility method to instantiate an instance of the specified class. | |||||
| */ | |||||
| private Object createObject( final Class type ) | |||||
| throws Exception | |||||
| { | |||||
| try | |||||
| { | |||||
| return type.newInstance(); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "create-object.error", | |||||
| type.getName() ); | |||||
| throw new ConfigurationException( message, e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,395 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| import java.lang.reflect.Method; | |||||
| import java.lang.reflect.Modifier; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Collection; | |||||
| import java.util.HashMap; | |||||
| import java.util.Iterator; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * An object configurer which uses reflection to determine the properties | |||||
| * of a class. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class DefaultObjectConfigurer | |||||
| implements ObjectConfigurer | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultObjectConfigurer.class ); | |||||
| private final Class m_class; | |||||
| /** | |||||
| * Adder property configurers. (For XML elements) | |||||
| */ | |||||
| private final HashMap m_adders = new HashMap(); | |||||
| /** | |||||
| * Setter property configurers. (For XML attributes) | |||||
| */ | |||||
| private final HashMap m_setters = new HashMap(); | |||||
| /** | |||||
| * The typed property configurer. | |||||
| */ | |||||
| private PropertyConfigurer m_typedPropertyConfigurer; | |||||
| /** | |||||
| * Content configurer. | |||||
| */ | |||||
| private PropertyConfigurer m_contentConfigurer; | |||||
| /** | |||||
| * Total number of properties. | |||||
| */ | |||||
| private int m_propCount; | |||||
| /** | |||||
| * Creates an object configurer for a particular class. The newly | |||||
| * created configurer will not handle any attributes, elements, or content. | |||||
| * Use the various <code>enable</code> methods to enable handling of these. | |||||
| */ | |||||
| private DefaultObjectConfigurer( final Class classInfo ) | |||||
| { | |||||
| m_class = classInfo; | |||||
| } | |||||
| /** | |||||
| * Enables all properties and content handling. | |||||
| */ | |||||
| private void enableAll() | |||||
| throws ConfigurationException | |||||
| { | |||||
| enableSetters(); | |||||
| enableAdders(); | |||||
| enableTypedAdder(); | |||||
| enableContent(); | |||||
| } | |||||
| /** | |||||
| * Enables all setters. | |||||
| */ | |||||
| private void enableSetters() | |||||
| throws ConfigurationException | |||||
| { | |||||
| // Locate all the setter methods | |||||
| final Collection methods = findMethods( "set", false ); | |||||
| // Create a configurer for each setter | |||||
| final Iterator iterator = methods.iterator(); | |||||
| while( iterator.hasNext() ) | |||||
| { | |||||
| final Method method = (Method)iterator.next(); | |||||
| final Class type = method.getParameterTypes()[ 0 ]; | |||||
| final String propName = extractName( 3, method.getName() ); | |||||
| final DefaultPropertyConfigurer setter = | |||||
| new DefaultPropertyConfigurer( getPropertyCount(), | |||||
| type, | |||||
| method, | |||||
| 1 ); | |||||
| m_setters.put( propName, setter ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Enables all adders. | |||||
| */ | |||||
| private void enableAdders() | |||||
| throws ConfigurationException | |||||
| { | |||||
| // Locate all the adder methods | |||||
| final Collection methods = findMethods( "add", false ); | |||||
| final Iterator iterator = methods.iterator(); | |||||
| while( iterator.hasNext() ) | |||||
| { | |||||
| final Method method = (Method)iterator.next(); | |||||
| final String methodName = method.getName(); | |||||
| // Skip the text content method | |||||
| if( methodName.equals( "addContent" ) ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| final Class type = method.getParameterTypes()[ 0 ]; | |||||
| final String propName = extractName( 3, methodName ); | |||||
| final DefaultPropertyConfigurer configurer = | |||||
| new DefaultPropertyConfigurer( getPropertyCount(), | |||||
| type, | |||||
| method, | |||||
| Integer.MAX_VALUE ); | |||||
| m_adders.put( propName, configurer ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Enables the typed adder. | |||||
| */ | |||||
| private void enableTypedAdder() | |||||
| throws ConfigurationException | |||||
| { | |||||
| final Collection methods = findMethods( "add", true ); | |||||
| if( methods.size() == 0 ) | |||||
| { | |||||
| return; | |||||
| } | |||||
| final Method method = (Method)methods.iterator().next(); | |||||
| final Class type = method.getParameterTypes()[ 0 ]; | |||||
| // TODO - this isn't necessary | |||||
| if( !type.isInterface() ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "typed-adder-non-interface.error", | |||||
| m_class.getName(), | |||||
| type.getName() ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| m_typedPropertyConfigurer | |||||
| = new DefaultPropertyConfigurer( getPropertyCount(), | |||||
| type, | |||||
| method, | |||||
| Integer.MAX_VALUE ); | |||||
| } | |||||
| /** | |||||
| * Enables text content. | |||||
| */ | |||||
| private void enableContent() | |||||
| throws ConfigurationException | |||||
| { | |||||
| // Locate the 'addContent' methods, which return void, and take | |||||
| // a single parameter. | |||||
| final Collection methods = findMethods( "addContent", true ); | |||||
| if( methods.size() == 0 ) | |||||
| { | |||||
| return; | |||||
| } | |||||
| final Method method = (Method)methods.iterator().next(); | |||||
| final Class type = method.getParameterTypes()[ 0 ]; | |||||
| m_contentConfigurer = new DefaultPropertyConfigurer( getPropertyCount(), | |||||
| type, | |||||
| method, | |||||
| 1 ); | |||||
| } | |||||
| /** | |||||
| * Locate all methods whose name starts with a particular | |||||
| * prefix, and which are non-static, return void, and take a single | |||||
| * non-array parameter. If there are more than one matching methods of | |||||
| * a given name, the method that takes a String parameter (if any) is | |||||
| * ignored. If after that there are more than one matching methods of | |||||
| * a given name, an exception is thrown. | |||||
| * | |||||
| * @return Map from property name -> Method object for that property. | |||||
| */ | |||||
| private Collection findMethods( final String prefix, | |||||
| final boolean exactMatch ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final Map methods = new HashMap(); | |||||
| final List allMethods = findMethodsWithPrefix( prefix, exactMatch ); | |||||
| final Iterator iterator = allMethods.iterator(); | |||||
| while( iterator.hasNext() ) | |||||
| { | |||||
| final Method method = (Method)iterator.next(); | |||||
| final String methodName = method.getName(); | |||||
| if( Void.TYPE != method.getReturnType() || | |||||
| 1 != method.getParameterTypes().length || | |||||
| method.getParameterTypes()[ 0 ].isArray() ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| // Extract property name | |||||
| final Class type = method.getParameterTypes()[ 0 ]; | |||||
| // Add to the adders map | |||||
| if( methods.containsKey( methodName ) ) | |||||
| { | |||||
| final Method candidate = (Method)methods.get( methodName ); | |||||
| final Class currentType = candidate.getParameterTypes()[ 0 ]; | |||||
| // Ditch the string version, if any | |||||
| if( currentType != String.class && type == String.class ) | |||||
| { | |||||
| // New type is string, and current type is not. Ignore | |||||
| // the new method | |||||
| continue; | |||||
| } | |||||
| else if( currentType != String.class || type == String.class ) | |||||
| { | |||||
| // Both are string (which would be odd), or both are not string | |||||
| final String message = | |||||
| REZ.getString( "multiple-methods-for-element.error", | |||||
| m_class.getName(), | |||||
| methodName ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| // Else, current type is string, and new type is not, so | |||||
| // continue below, and replace the current method | |||||
| } | |||||
| methods.put( methodName, method ); | |||||
| } | |||||
| return methods.values(); | |||||
| } | |||||
| private int getPropertyCount() | |||||
| { | |||||
| return m_propCount++; | |||||
| } | |||||
| /** | |||||
| * Locates the configurer for a particular class. | |||||
| */ | |||||
| public static ObjectConfigurer getConfigurer( final Class classInfo ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final DefaultObjectConfigurer configurer = new DefaultObjectConfigurer( classInfo ); | |||||
| configurer.enableAll(); | |||||
| return configurer; | |||||
| } | |||||
| /** | |||||
| * Starts the configuration of an object. | |||||
| */ | |||||
| public ConfigurationState startConfiguration( Object object ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| return new ConfigurationState( this, object, getPropertyCount() ); | |||||
| } | |||||
| /** | |||||
| * Finishes the configuration of an object, performing any final | |||||
| * validation and type conversion. | |||||
| */ | |||||
| public Object finishConfiguration( final ConfigurationState state ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| // Make sure there are no pending created objects | |||||
| final ConfigurationState defState = (ConfigurationState)state; | |||||
| return defState.getObject(); | |||||
| } | |||||
| /** | |||||
| * Returns a configurer for an element of this class. | |||||
| */ | |||||
| public PropertyConfigurer getAdder( final String name ) | |||||
| { | |||||
| return (PropertyConfigurer)m_adders.get( name ); | |||||
| } | |||||
| /** | |||||
| * Returns a configurer for an element of this class. | |||||
| */ | |||||
| public PropertyConfigurer getSetter( final String name ) | |||||
| { | |||||
| return (PropertyConfigurer)m_setters.get( name ); | |||||
| } | |||||
| /** | |||||
| * Returns a configurer for the typed property of this class. | |||||
| */ | |||||
| public PropertyConfigurer getTypedProperty() | |||||
| { | |||||
| return m_typedPropertyConfigurer; | |||||
| } | |||||
| /** | |||||
| * Returns a configurer for the content of this class. | |||||
| */ | |||||
| public PropertyConfigurer getContentConfigurer() | |||||
| { | |||||
| return m_contentConfigurer; | |||||
| } | |||||
| /** | |||||
| * Extracts a property name from a Java method name. | |||||
| * | |||||
| * <p>Removes the prefix, inserts '-' before each uppercase character | |||||
| * (except the first), then converts all to lowercase. | |||||
| */ | |||||
| private String extractName( final int prefixLen, final String methodName ) | |||||
| { | |||||
| final StringBuffer sb = new StringBuffer( methodName ); | |||||
| sb.delete( 0, prefixLen ); | |||||
| //Contains the index that we are up to in string buffer. | |||||
| //May not be equal to i as length of string buffer may change | |||||
| int index = 0; | |||||
| final int size = sb.length(); | |||||
| for( int i = 0; i < size; i++ ) | |||||
| { | |||||
| char ch = sb.charAt( index ); | |||||
| if( Character.isUpperCase( ch ) ) | |||||
| { | |||||
| if( index > 0 ) | |||||
| { | |||||
| sb.insert( index, '-' ); | |||||
| index++; | |||||
| } | |||||
| sb.setCharAt( index, Character.toLowerCase( ch ) ); | |||||
| } | |||||
| index++; | |||||
| } | |||||
| return sb.toString(); | |||||
| } | |||||
| /** | |||||
| * Locates all non-static methods whose name starts with a particular | |||||
| * prefix. | |||||
| */ | |||||
| private List findMethodsWithPrefix( final String prefix, | |||||
| final boolean exactMatch ) | |||||
| { | |||||
| final ArrayList matches = new ArrayList(); | |||||
| final int prefixLen = prefix.length(); | |||||
| final Method[] methods = m_class.getMethods(); | |||||
| for( int i = 0; i < methods.length; i++ ) | |||||
| { | |||||
| final Method method = methods[ i ]; | |||||
| final String methodName = method.getName(); | |||||
| if( Modifier.isStatic( method.getModifiers() ) ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| if( methodName.length() < prefixLen || !methodName.startsWith( prefix ) ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| if( exactMatch && methodName.length() != prefixLen ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| matches.add( method ); | |||||
| } | |||||
| return matches; | |||||
| } | |||||
| } | |||||
| @@ -1,139 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| import java.lang.reflect.InvocationTargetException; | |||||
| import java.lang.reflect.Method; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * The default property configurer implementation, which uses reflection to | |||||
| * create and set property values. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class DefaultPropertyConfigurer | |||||
| implements PropertyConfigurer | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultPropertyConfigurer.class ); | |||||
| private final int m_propertyIndex; | |||||
| private final Class m_type; | |||||
| private final Method m_method; | |||||
| private final int m_maxCount; | |||||
| public DefaultPropertyConfigurer( final int propIndex, | |||||
| final Class type, | |||||
| final Method method, | |||||
| final int maxCount ) | |||||
| { | |||||
| m_propertyIndex = propIndex; | |||||
| if( type.isPrimitive() ) | |||||
| { | |||||
| m_type = getComplexTypeFor( type ); | |||||
| } | |||||
| else | |||||
| { | |||||
| m_type = type; | |||||
| } | |||||
| m_method = method; | |||||
| m_maxCount = maxCount; | |||||
| if( null == m_method ) | |||||
| { | |||||
| throw new NullPointerException( "method" ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Returns the type of the element. | |||||
| */ | |||||
| public Class getType() | |||||
| { | |||||
| return m_type; | |||||
| } | |||||
| /** | |||||
| * Adds a value for this property, to an object. | |||||
| */ | |||||
| public void addValue( final ConfigurationState state, final Object value ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final ConfigurationState defState = (ConfigurationState)state; | |||||
| // Check the property count | |||||
| if( defState.getPropertyCount( m_propertyIndex ) >= m_maxCount ) | |||||
| { | |||||
| final String message = REZ.getString( "too-many-values.error" ); | |||||
| throw new ConfigurationException( message ); | |||||
| } | |||||
| defState.incPropertyCount( m_propertyIndex ); | |||||
| try | |||||
| { | |||||
| // Add the value | |||||
| m_method.invoke( defState.getObject(), new Object[]{value} ); | |||||
| } | |||||
| catch( final InvocationTargetException ite ) | |||||
| { | |||||
| final Throwable cause = ite.getTargetException(); | |||||
| throw new ConfigurationException( cause.getMessage(), cause ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| throw new ConfigurationException( e.getMessage(), e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Determines the complex type for a prmitive type. | |||||
| */ | |||||
| private Class getComplexTypeFor( final Class clazz ) | |||||
| { | |||||
| if( String.class == clazz ) | |||||
| { | |||||
| return String.class; | |||||
| } | |||||
| else if( Integer.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Integer.class; | |||||
| } | |||||
| else if( Long.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Long.class; | |||||
| } | |||||
| else if( Short.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Short.class; | |||||
| } | |||||
| else if( Byte.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Byte.class; | |||||
| } | |||||
| else if( Boolean.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Boolean.class; | |||||
| } | |||||
| else if( Float.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Float.class; | |||||
| } | |||||
| else if( Double.TYPE.equals( clazz ) ) | |||||
| { | |||||
| return Double.class; | |||||
| } | |||||
| else | |||||
| { | |||||
| final String message = REZ.getString( "no-complex-type.error", clazz.getName() ); | |||||
| throw new IllegalArgumentException( message ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,19 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| /** | |||||
| * A marker exception that is thrown when an unknown property is encountered. | |||||
| * | |||||
| * @author Adam Murdoch | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class NoSuchPropertyException | |||||
| extends Exception | |||||
| { | |||||
| } | |||||
| @@ -1,75 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * Configures objects of a particular class. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| interface ObjectConfigurer | |||||
| { | |||||
| /** | |||||
| * Starts the configuration of an object. | |||||
| * | |||||
| * @param object The object about to be configured. | |||||
| * @return The state object, used to track type-specific state during | |||||
| * configuration. | |||||
| * @throws ConfigurationException On error starting the configuration. | |||||
| */ | |||||
| ConfigurationState startConfiguration( Object object ) | |||||
| throws ConfigurationException; | |||||
| /** | |||||
| * Finishes the configuration of an object, performing any final | |||||
| * validation and type conversion. | |||||
| * | |||||
| * @param state The state object. | |||||
| * @return The configured object. | |||||
| * @throws ConfigurationException On error finishing the configurtion. | |||||
| */ | |||||
| Object finishConfiguration( ConfigurationState state ) | |||||
| throws ConfigurationException; | |||||
| /** | |||||
| * Returns a configurer for a atribute property of this class. | |||||
| * | |||||
| * @param name The attribute name. | |||||
| * @return A configurer for the property, or null if the property is not | |||||
| * valid for this class. | |||||
| */ | |||||
| PropertyConfigurer getSetter( String name ); | |||||
| /** | |||||
| * Returns a configurer for a element property of this class. | |||||
| * | |||||
| * @param name The element name. | |||||
| * @return A configurer for the property, or null if the property is not | |||||
| * valid for this class. | |||||
| */ | |||||
| PropertyConfigurer getAdder( String name ); | |||||
| /** | |||||
| * Returns a configurer for the text content of this class. | |||||
| * | |||||
| * @return A configurer for the text content, or null if the class does not | |||||
| * support text content. | |||||
| */ | |||||
| PropertyConfigurer getContentConfigurer(); | |||||
| /** | |||||
| * Returns a configurer for the typed property of this class. | |||||
| * | |||||
| * @return A configurer for the typed property, or null if the class | |||||
| * does not have a typed property. | |||||
| */ | |||||
| PropertyConfigurer getTypedProperty(); | |||||
| } | |||||
| @@ -1,36 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * Configures a property of an object. | |||||
| * TODO - axe createValue(). | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| interface PropertyConfigurer | |||||
| { | |||||
| /** | |||||
| * Returns the type of this property. | |||||
| */ | |||||
| Class getType(); | |||||
| /** | |||||
| * Adds a value for this property, to an object. | |||||
| * | |||||
| * @param state The state object, representing the object being configured. | |||||
| * @param value The property value. This must be assignable to the type | |||||
| * returned by {@link #getType}. | |||||
| * @throws ConfigurationException If the property cannot be set. | |||||
| */ | |||||
| void addValue( ConfigurationState state, Object value ) | |||||
| throws ConfigurationException; | |||||
| } | |||||
| @@ -1,39 +0,0 @@ | |||||
| /* | |||||
| * 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.components.configurer; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| /** | |||||
| * A marker exception. | |||||
| * | |||||
| * TODO - this should extend ConfigurationException, except it is final. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class ReportableConfigurationException | |||||
| extends Exception | |||||
| { | |||||
| private ConfigurationException m_cause; | |||||
| public ReportableConfigurationException( String s ) | |||||
| { | |||||
| m_cause = new ConfigurationException( s ); | |||||
| } | |||||
| public ReportableConfigurationException( String s, Throwable throwable ) | |||||
| { | |||||
| m_cause = new ConfigurationException( s, throwable ); | |||||
| } | |||||
| public ConfigurationException getCause() | |||||
| { | |||||
| return m_cause; | |||||
| } | |||||
| } | |||||
| @@ -1,17 +0,0 @@ | |||||
| create-object.error=Could not create an object of class {0}. | |||||
| extra-config-for-ref.error=A reference element can only include an "id" attribute. | |||||
| mismatch-ref-types.error=Could not convert reference "{0}" to the type expected for property "{1}". | |||||
| incompatible-element-types.error=Incompatible creator and adder/setter methods found in class {0} for property "{1}". | |||||
| multiple-methods-for-element.error=Multiple non-String {1}() methods found in class {0}. | |||||
| too-many-values.error=Too many values for this property. | |||||
| no-complex-type.error=Can not get complex type for non-primitive type {0}. | |||||
| no-such-attribute.error=Element <{0}> does not support attribute "{1}". | |||||
| bad-set-attribute.error=Could not set attribute "{1}" for element <{0}>. | |||||
| bad-set-class-attribute.error=Could not set attribute "{0}" for object of class {1}. | |||||
| no-such-element.error=Element <{0}> does not support nested <{1}> elements. | |||||
| no-content.error=Element <{0} does not support text content. | |||||
| 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. | |||||
| create-typed-object.error=Could not create an object of type "{0}" of class {1}. | |||||
| unknown-reference.error=Could not find referenced object "{0}". | |||||
| bad-configure-element.error=Could not configure element <{0}>. | |||||
| @@ -1,70 +0,0 @@ | |||||
| /* | |||||
| * 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.components.converter; | |||||
| import org.apache.aut.converter.Converter; | |||||
| import org.apache.aut.converter.AbstractMasterConverter; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||||
| import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| /** | |||||
| * Converter engine to handle converting between types. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultMasterConverter | |||||
| extends AbstractMasterConverter | |||||
| implements ConverterRegistry, Serviceable | |||||
| { | |||||
| private TypeManager m_typeManager; | |||||
| /** | |||||
| * Retrieve relevent services needed to deploy. | |||||
| * | |||||
| * @param serviceManager the ServiceManager | |||||
| * @exception ServiceException if an error occurs | |||||
| */ | |||||
| public void service( final ServiceManager serviceManager ) | |||||
| throws ServiceException | |||||
| { | |||||
| m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||||
| } | |||||
| /** | |||||
| * Register a converter | |||||
| * | |||||
| * @param className the className of converter | |||||
| * @param source the source classname | |||||
| * @param destination the destination classname | |||||
| */ | |||||
| public void registerConverter( final String className, | |||||
| final String source, | |||||
| final String destination ) | |||||
| { | |||||
| super.registerConverter( className, source, destination ); | |||||
| } | |||||
| /** | |||||
| * Create an instance of converter with specified name. | |||||
| * | |||||
| * @param name the name of converter | |||||
| * @return the created converter instance | |||||
| * @throws Exception if converter can not be created. | |||||
| */ | |||||
| protected Converter createConverter( final String name ) | |||||
| throws Exception | |||||
| { | |||||
| final TypeFactory factory = m_typeManager.getFactory( Converter.ROLE ); | |||||
| return (Converter)factory.create( name ); | |||||
| } | |||||
| } | |||||
| @@ -1,289 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import java.io.File; | |||||
| import java.net.URL; | |||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| import org.apache.aut.converter.Converter; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||||
| import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||||
| import org.apache.myrmidon.interfaces.deployer.ConverterDefinition; | |||||
| import org.apache.myrmidon.interfaces.deployer.Deployer; | |||||
| import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
| import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||||
| import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||||
| import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
| import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||||
| import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| /** | |||||
| * This class deploys roles, types and services from a typelib. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultDeployer | |||||
| extends AbstractLogEnabled | |||||
| implements Deployer, Serviceable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultDeployer.class ); | |||||
| // The components used to deploy | |||||
| private ConverterRegistry m_converterRegistry; | |||||
| private TypeManager m_typeManager; | |||||
| private RoleManager m_roleManager; | |||||
| private ClassLoaderManager m_classLoaderManager; | |||||
| /** Map from ClassLoader to the deployer for that class loader. */ | |||||
| private final Map m_classLoaderDeployers = new HashMap(); | |||||
| /** | |||||
| * Retrieve relevent services needed to deploy. | |||||
| * | |||||
| * @param serviceManager the ServiceManager | |||||
| * @exception ServiceException if an error occurs | |||||
| */ | |||||
| public void service( final ServiceManager serviceManager ) | |||||
| throws ServiceException | |||||
| { | |||||
| m_converterRegistry = (ConverterRegistry)serviceManager.lookup( ConverterRegistry.ROLE ); | |||||
| m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||||
| m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||||
| m_classLoaderManager = (ClassLoaderManager)serviceManager.lookup( ClassLoaderManager.ROLE ); | |||||
| } | |||||
| /** | |||||
| * Creates a child deployer. | |||||
| */ | |||||
| public Deployer createChildDeployer( final ServiceManager componentManager ) | |||||
| throws ServiceException | |||||
| { | |||||
| final DefaultDeployer child = new DefaultDeployer(); | |||||
| setupLogger( child ); | |||||
| child.service( componentManager ); | |||||
| return child; | |||||
| } | |||||
| /** | |||||
| * Returns the deployer for a ClassLoader, creating the deployer if | |||||
| * necessary. | |||||
| */ | |||||
| public TypeDeployer createDeployer( final ClassLoader loader ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| return createDeployment( loader, null ); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "deploy-from-classloader.error", loader ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Returns the deployer for a type library, creating the deployer if | |||||
| * necessary. | |||||
| */ | |||||
| public TypeDeployer createDeployer( final File file ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| final ClassLoader classLoader = m_classLoaderManager.getClassLoader( file ); | |||||
| return createDeployment( classLoader, file.toURL() ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "deploy-from-file.error", file ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 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 ) | |||||
| { | |||||
| deployment = new Deployment( this, loader ); | |||||
| setupLogger( deployment ); | |||||
| deployment.loadDescriptors( jarUrl ); | |||||
| m_classLoaderDeployers.put( loader, deployment ); | |||||
| } | |||||
| return deployment; | |||||
| } | |||||
| /** | |||||
| * Deploys a service. | |||||
| */ | |||||
| public void deployService( final Deployment deployment, | |||||
| final ServiceDefinition definition ) | |||||
| throws Exception | |||||
| { | |||||
| final String roleShorthand = definition.getRoleShorthand(); | |||||
| final String roleName = getRole( roleShorthand ).getName(); | |||||
| final String factoryClassName = definition.getFactoryClass(); | |||||
| handleType( deployment, ServiceFactory.ROLE, roleName, factoryClassName ); | |||||
| } | |||||
| /** | |||||
| * Handles a type definition. | |||||
| */ | |||||
| public void deployType( final Deployment deployment, | |||||
| final TypeDefinition typeDef ) | |||||
| throws Exception | |||||
| { | |||||
| final String typeName = typeDef.getName(); | |||||
| final String roleShorthand = typeDef.getRole(); | |||||
| final String className = typeDef.getClassname(); | |||||
| if( null == className ) | |||||
| { | |||||
| final String message = REZ.getString( "typedef.no-classname.error" ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| if( typeDef instanceof ConverterDefinition ) | |||||
| { | |||||
| // Validate the definition | |||||
| final ConverterDefinition converterDef = (ConverterDefinition)typeDef; | |||||
| final String srcClass = converterDef.getSourceType(); | |||||
| final String destClass = converterDef.getDestinationType(); | |||||
| if( null == srcClass ) | |||||
| { | |||||
| final String message = REZ.getString( "converterdef.no-source.error" ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| if( null == destClass ) | |||||
| { | |||||
| final String message = REZ.getString( "converterdef.no-destination.error" ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| // Deploy the converter | |||||
| handleConverter( deployment, className, srcClass, destClass ); | |||||
| } | |||||
| else | |||||
| { | |||||
| // Validate the definition | |||||
| if( null == roleShorthand ) | |||||
| { | |||||
| final String message = REZ.getString( "typedef.no-role.error" ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| else if( null == typeName ) | |||||
| { | |||||
| final String message = REZ.getString( "typedef.no-name.error" ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| // Deploy general-purpose type | |||||
| final String roleName = getRole( roleShorthand ).getName(); | |||||
| handleType( deployment, roleName, typeName, className ); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "register-type.notice", roleShorthand, typeName ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Handles a type definition. | |||||
| */ | |||||
| private void handleType( final Deployment deployment, | |||||
| final String roleName, | |||||
| final String typeName, | |||||
| final String className ) | |||||
| throws Exception | |||||
| { | |||||
| // TODO - detect duplicates | |||||
| final DefaultTypeFactory factory = deployment.getFactory( roleName ); | |||||
| factory.addNameClassMapping( typeName, className ); | |||||
| m_typeManager.registerType( roleName, typeName, factory ); | |||||
| } | |||||
| /** | |||||
| * Handles a converter definition. | |||||
| */ | |||||
| private void handleConverter( final Deployment deployment, | |||||
| final String className, | |||||
| final String source, | |||||
| final String destination ) | |||||
| throws Exception | |||||
| { | |||||
| m_converterRegistry.registerConverter( className, source, destination ); | |||||
| final DefaultTypeFactory factory = deployment.getFactory( Converter.ROLE ); | |||||
| factory.addNameClassMapping( className, className ); | |||||
| m_typeManager.registerType( Converter.ROLE, className, factory ); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "register-converter.notice", source, destination ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Handles a role definition. | |||||
| */ | |||||
| public void deployRole( final Deployment deployment, | |||||
| final RoleDefinition roleDef ) | |||||
| throws Exception | |||||
| { | |||||
| final String name = roleDef.getShortHand(); | |||||
| final String role = roleDef.getRoleName(); | |||||
| final Class type = deployment.getClassLoader().loadClass( role ); | |||||
| final RoleInfo roleInfo = new RoleInfo( role, name, type, null ); | |||||
| m_roleManager.addRole( roleInfo ); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String debugMessage = REZ.getString( "register-role.notice", role, name ); | |||||
| getLogger().debug( debugMessage ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Locates a role, from its shorthand. | |||||
| */ | |||||
| private RoleInfo getRole( final String roleShorthand ) | |||||
| throws DeploymentException | |||||
| { | |||||
| final RoleInfo roleInfo = m_roleManager.getRoleByShorthandName( roleShorthand ); | |||||
| if( null == roleInfo ) | |||||
| { | |||||
| final String message = REZ.getString( "unknown-role4name.error", roleShorthand ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| return roleInfo; | |||||
| } | |||||
| } | |||||
| @@ -1,363 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import java.io.FileNotFoundException; | |||||
| import java.net.URL; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Enumeration; | |||||
| import java.util.HashMap; | |||||
| 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.configuration.SAXConfigurationHandler; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
| import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||||
| import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||||
| import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||||
| import org.xml.sax.XMLReader; | |||||
| /** | |||||
| * This class deploys type libraries from a ClassLoader into a registry. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class Deployment | |||||
| extends AbstractLogEnabled | |||||
| implements TypeDeployer | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( Deployment.class ); | |||||
| private static final String TYPE_DESCRIPTOR_NAME = "META-INF/ant-descriptor.xml"; | |||||
| private static final String ROLE_DESCRIPTOR_NAME = "META-INF/ant-roles.xml"; | |||||
| private static final String SERVICE_DESCRIPTOR_NAME = "META-INF/ant-services.xml"; | |||||
| private ClassLoader m_classLoader; | |||||
| private DefaultDeployer m_deployer; | |||||
| private TypeDescriptor[] m_descriptors; | |||||
| private ServiceDescriptor[] m_services; | |||||
| // TODO - create and configure these in DefaultDeployer | |||||
| private DescriptorBuilder m_roleBuilder = new RoleDescriptorBuilder(); | |||||
| private DescriptorBuilder m_typeBuilder = new TypeDescriptorBuilder(); | |||||
| private DescriptorBuilder m_serviceBuilder = new ServiceDescriptorBuilder(); | |||||
| /** Map from role Class -> DefaultTypeFactory for that role. */ | |||||
| private Map m_factories = new HashMap(); | |||||
| public Deployment( final DefaultDeployer deployer, final ClassLoader classLoader ) | |||||
| { | |||||
| m_deployer = deployer; | |||||
| m_classLoader = classLoader; | |||||
| } | |||||
| /** | |||||
| * Load the descriptors. Deploys all roles, then loads the descriptors | |||||
| * for, but does not deploy, all the types. | |||||
| * | |||||
| * @param jarUrl The URL for the typelib, used to locate the descriptors. | |||||
| * If null, the resources from the classloader are used. | |||||
| */ | |||||
| public void loadDescriptors( final URL jarUrl ) | |||||
| throws Exception | |||||
| { | |||||
| // 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 ); | |||||
| // Build the role descriptors | |||||
| final ArrayList roleUrls = locateResources( ROLE_DESCRIPTOR_NAME, jarUrl ); | |||||
| final ArrayList roleDescriptors = | |||||
| buildDescriptors( roleUrls, m_roleBuilder, parser, handler ); | |||||
| // Deploy the roles | |||||
| // TODO - need to defer this | |||||
| final int roleCount = roleDescriptors.size(); | |||||
| for( int i = 0; i < roleCount; i++ ) | |||||
| { | |||||
| final RoleDescriptor descriptor = (RoleDescriptor)roleDescriptors.get( i ); | |||||
| deployRoles( descriptor ); | |||||
| } | |||||
| // Build the type descriptors | |||||
| final ArrayList typeUrls = locateResources( TYPE_DESCRIPTOR_NAME, jarUrl ); | |||||
| final ArrayList typeDescriptors = | |||||
| buildDescriptors( typeUrls, m_typeBuilder, parser, handler ); | |||||
| m_descriptors = (TypeDescriptor[])typeDescriptors.toArray | |||||
| ( new TypeDescriptor[ typeDescriptors.size() ] ); | |||||
| // Build the service descriptors | |||||
| final ArrayList serviceUrls = locateResources( SERVICE_DESCRIPTOR_NAME, jarUrl ); | |||||
| final ArrayList serviceDescriptors = | |||||
| buildDescriptors( serviceUrls, m_serviceBuilder, parser, handler ); | |||||
| m_services = (ServiceDescriptor[])serviceDescriptors.toArray | |||||
| ( new ServiceDescriptor[ serviceDescriptors.size() ] ); | |||||
| } | |||||
| /** | |||||
| * Returns the type factory for a role. | |||||
| */ | |||||
| public DefaultTypeFactory getFactory( final String roleName ) | |||||
| { | |||||
| DefaultTypeFactory factory = (DefaultTypeFactory)m_factories.get( roleName ); | |||||
| if( null == factory ) | |||||
| { | |||||
| factory = new DefaultTypeFactory( m_classLoader ); | |||||
| m_factories.put( roleName, factory ); | |||||
| } | |||||
| return factory; | |||||
| } | |||||
| /** | |||||
| * Returns the classloader for this deployment. | |||||
| */ | |||||
| public ClassLoader getClassLoader() | |||||
| { | |||||
| return m_classLoader; | |||||
| } | |||||
| /** | |||||
| * Deploys everything in the type library. | |||||
| */ | |||||
| public void deployAll() | |||||
| throws DeploymentException | |||||
| { | |||||
| // Deploy types | |||||
| for( int i = 0; i < m_descriptors.length; i++ ) | |||||
| { | |||||
| TypeDescriptor descriptor = m_descriptors[ i ]; | |||||
| deployTypes( descriptor ); | |||||
| } | |||||
| // Deploy services | |||||
| for( int i = 0; i < m_services.length; i++ ) | |||||
| { | |||||
| final ServiceDescriptor descriptor = m_services[ i ]; | |||||
| deployServices( descriptor ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Deploys a single type in the type library. | |||||
| */ | |||||
| public void deployType( final String roleShorthand, final String typeName ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| // Locate the definition for the type | |||||
| for( int i = 0; i < m_descriptors.length; i++ ) | |||||
| { | |||||
| final TypeDescriptor descriptor = m_descriptors[ i ]; | |||||
| final TypeDefinition[] definitions = descriptor.getDefinitions(); | |||||
| for( int j = 0; j < definitions.length; j++ ) | |||||
| { | |||||
| TypeDefinition definition = definitions[ j ]; | |||||
| if( definition.getRole().equals( roleShorthand ) | |||||
| && definition.getName().equals( typeName ) ) | |||||
| { | |||||
| // Found the definition - deploy it. Note that we | |||||
| // keep looking for matching types, and let the deployer | |||||
| // deal with duplicates | |||||
| m_deployer.deployType( this, definition ); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "deploy-type.error", roleShorthand, typeName ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Deploys a single type from the type library. | |||||
| */ | |||||
| public void deployType( final TypeDefinition typeDef ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| m_deployer.deployType( this, typeDef ); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "deploy-type.error", | |||||
| typeDef.getRole(), typeDef.getName() ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Builds descriptors. | |||||
| */ | |||||
| private ArrayList buildDescriptors( final ArrayList urls, | |||||
| final DescriptorBuilder builder, | |||||
| final XMLReader parser, | |||||
| final SAXConfigurationHandler handler ) | |||||
| throws Exception | |||||
| { | |||||
| final ArrayList descriptors = new ArrayList(); | |||||
| final int size = urls.size(); | |||||
| for( int i = 0; i < size; i++ ) | |||||
| { | |||||
| final String url = (String)urls.get( i ); | |||||
| // Parse the file | |||||
| parser.parse( url ); | |||||
| final TypelibDescriptor descriptor = | |||||
| builder.createDescriptor( handler.getConfiguration(), url ); | |||||
| descriptors.add( descriptor ); | |||||
| } | |||||
| return descriptors; | |||||
| } | |||||
| /** | |||||
| * Locates all resources of a particular name. | |||||
| */ | |||||
| private ArrayList locateResources( final String resource, final URL jarUrl ) | |||||
| throws Exception | |||||
| { | |||||
| final ArrayList urls = new ArrayList(); | |||||
| if( null != jarUrl ) | |||||
| { | |||||
| final String systemID = "jar:" + jarUrl + "!/" + resource; | |||||
| try | |||||
| { | |||||
| // Probe the resource | |||||
| final URL url = new URL( systemID ); | |||||
| url.openStream().close(); | |||||
| // Add to the list | |||||
| urls.add( systemID ); | |||||
| } | |||||
| catch( FileNotFoundException e ) | |||||
| { | |||||
| // Ignore | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| final Enumeration enum = m_classLoader.getResources( resource ); | |||||
| while( enum.hasMoreElements() ) | |||||
| { | |||||
| urls.add( enum.nextElement().toString() ); | |||||
| } | |||||
| } | |||||
| return urls; | |||||
| } | |||||
| /** | |||||
| * Deploys the roles from a role descriptor. | |||||
| */ | |||||
| private void deployRoles( final RoleDescriptor descriptor ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "url-deploy-roles.notice", descriptor.getUrl() ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| final RoleDefinition[] definitions = descriptor.getDefinitions(); | |||||
| for( int i = 0; i < definitions.length; i++ ) | |||||
| { | |||||
| final RoleDefinition definition = definitions[ i ]; | |||||
| m_deployer.deployRole( this, definition ); | |||||
| } | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "deploy-roles.error", descriptor.getUrl() ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Deploys all types from a typelib descriptor. | |||||
| */ | |||||
| private void deployTypes( final TypeDescriptor descriptor ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "url-deploy-types.notice", descriptor.getUrl() ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| // Deploy all the types | |||||
| final TypeDefinition[] definitions = descriptor.getDefinitions(); | |||||
| for( int i = 0; i < definitions.length; i++ ) | |||||
| { | |||||
| final TypeDefinition definition = definitions[ i ]; | |||||
| m_deployer.deployType( this, definition ); | |||||
| } | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "deploy-types.error", descriptor.getUrl() ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Deploys all services from a typelib descriptor. | |||||
| */ | |||||
| private void deployServices( final ServiceDescriptor descriptor ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "url-deploy-services.notice", descriptor.getUrl() ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| // Deploy the services | |||||
| final ServiceDefinition[] definitions = descriptor.getDefinitions(); | |||||
| for( int i = 0; i < definitions.length; i++ ) | |||||
| { | |||||
| final ServiceDefinition definition = definitions[ i ]; | |||||
| m_deployer.deployService( this, definition ); | |||||
| } | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "deploy-services.error", descriptor.getUrl() ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,27 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
| /** | |||||
| * Builds a descriptor. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| interface DescriptorBuilder | |||||
| { | |||||
| /** | |||||
| * Builds a descriptor from a set of configuration. | |||||
| */ | |||||
| TypelibDescriptor createDescriptor( Configuration config, | |||||
| String descriptorUrl ) | |||||
| throws DeploymentException; | |||||
| } | |||||
| @@ -1,27 +0,0 @@ | |||||
| register-converter.notice=Registered converter that converts from {0} to {1}. | |||||
| 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}". | |||||
| url-deploy-services.notice=Registering services from "{0}". | |||||
| deploy-from-classloader.error=Could not register types from ClassLoader. | |||||
| deploy-from-file.error=Could not register types from type library "{0}". | |||||
| deploy-roles.error=Could not register roles from "{0}". | |||||
| deploy-types.error=Could not register types from "{0}". | |||||
| deploy-services.error=Could not register services 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}". | |||||
| typedef.no-classname.error=Must specify the classname parameter. | |||||
| typedef.no-name.error=Must specify name parameter. | |||||
| typedef.no-role.error=Must specify type parameter. | |||||
| converterdef.no-source.error=Must specify the source-type parameter. | |||||
| converterdef.no-destination.error=Must specify the destination-type parameter. | |||||
| role-descriptor-version.error=Role descriptor version {0} is incompatible with current version {1}. | |||||
| build-role-descriptor.error=Could not build role descriptor from "{0}". | |||||
| type-descriptor-version.error=Type library descriptor version {0} is incompatible with current version {1}. | |||||
| build-type-descriptor.error=Could not build type library descriptor from "{0}". | |||||
| service-descriptor-version.error=Service descriptor version {0} is incompatible with current version {1}. | |||||
| build-service-descriptor.error=Could not build service descriptor from "{0}". | |||||
| @@ -1,36 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| /** | |||||
| * A role definition. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| */ | |||||
| class RoleDefinition | |||||
| { | |||||
| private final String m_roleName; | |||||
| private final String m_shortHand; | |||||
| public RoleDefinition( final String roleName, | |||||
| final String shortHand ) | |||||
| { | |||||
| m_roleName = roleName; | |||||
| m_shortHand = shortHand; | |||||
| } | |||||
| public String getRoleName() | |||||
| { | |||||
| return m_roleName; | |||||
| } | |||||
| public String getShortHand() | |||||
| { | |||||
| return m_shortHand; | |||||
| } | |||||
| } | |||||
| @@ -1,45 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| /** | |||||
| * A typelib role descriptor, which defines a set of roles. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class RoleDescriptor | |||||
| extends TypelibDescriptor | |||||
| { | |||||
| private final List m_definitions = new ArrayList(); | |||||
| public RoleDescriptor( final String url ) | |||||
| { | |||||
| super( url ); | |||||
| } | |||||
| /** | |||||
| * Returns the role definitions in the descriptor. | |||||
| */ | |||||
| public RoleDefinition[] getDefinitions() | |||||
| { | |||||
| return (RoleDefinition[])m_definitions.toArray | |||||
| ( new RoleDefinition[ m_definitions.size() ] ); | |||||
| } | |||||
| /** | |||||
| * Adds a role definition to the descriptor. | |||||
| */ | |||||
| public void addDefinition( final RoleDefinition def ) | |||||
| { | |||||
| m_definitions.add( def ); | |||||
| } | |||||
| } | |||||
| @@ -1,70 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.Version; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
| /** | |||||
| * Builds typelib role descriptors. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class RoleDescriptorBuilder | |||||
| implements DescriptorBuilder | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( RoleDescriptorBuilder.class ); | |||||
| private static final Version ROLE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||||
| /** | |||||
| * Builds a descriptor from a set of configuration. | |||||
| */ | |||||
| public TypelibDescriptor createDescriptor( final Configuration config, | |||||
| final String url ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| // Check version | |||||
| final String versionString = config.getAttribute( "version" ); | |||||
| final Version version = Version.getVersion( versionString ); | |||||
| if( !ROLE_DESCRIPTOR_VERSION.complies( version ) ) | |||||
| { | |||||
| final String message = REZ.getString( "role-descriptor-version.error", | |||||
| version, ROLE_DESCRIPTOR_VERSION ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| // Assemble the descriptor | |||||
| final RoleDescriptor descriptor = new RoleDescriptor( url ); | |||||
| // Extract each of the role elements | |||||
| final Configuration[] types = config.getChildren( "role" ); | |||||
| for( int i = 0; i < types.length; i++ ) | |||||
| { | |||||
| final String name = types[ i ].getAttribute( "shorthand" ); | |||||
| final String role = types[ i ].getAttribute( "name" ); | |||||
| final RoleDefinition roleDef = new RoleDefinition( role, name ); | |||||
| descriptor.addDefinition( roleDef ); | |||||
| } | |||||
| return descriptor; | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "build-role-descriptor.error", url ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,56 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| /** | |||||
| * A service definition. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class ServiceDefinition | |||||
| { | |||||
| private final String m_roleShorthand; | |||||
| private final String m_factoryClass; | |||||
| private final Configuration m_config; | |||||
| public ServiceDefinition( final String roleShorthand, | |||||
| final String factoryClass, | |||||
| final Configuration config ) | |||||
| { | |||||
| m_roleShorthand = roleShorthand; | |||||
| m_factoryClass = factoryClass; | |||||
| m_config = config; | |||||
| } | |||||
| /** | |||||
| * Returns the role that the service implements. | |||||
| */ | |||||
| public String getRoleShorthand() | |||||
| { | |||||
| return m_roleShorthand; | |||||
| } | |||||
| /** | |||||
| * Returns the name of the factory class for creating the service. | |||||
| */ | |||||
| public String getFactoryClass() | |||||
| { | |||||
| return m_factoryClass; | |||||
| } | |||||
| /** | |||||
| * Returns the service configuration. | |||||
| */ | |||||
| public Configuration getConfig() | |||||
| { | |||||
| return m_config; | |||||
| } | |||||
| } | |||||
| @@ -1,39 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| /** | |||||
| * A typelib service descriptor, which defines a set of services. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class ServiceDescriptor | |||||
| extends TypelibDescriptor | |||||
| { | |||||
| private final List m_services = new ArrayList(); | |||||
| public ServiceDescriptor( final String url ) | |||||
| { | |||||
| super( url ); | |||||
| } | |||||
| public ServiceDefinition[] getDefinitions() | |||||
| { | |||||
| return (ServiceDefinition[])m_services.toArray | |||||
| ( new ServiceDefinition[ m_services.size() ] ); | |||||
| } | |||||
| public void addDefinition( final ServiceDefinition definition ) | |||||
| { | |||||
| m_services.add( definition ); | |||||
| } | |||||
| } | |||||
| @@ -1,72 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.Version; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
| /** | |||||
| * Builds typelib service descriptors. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class ServiceDescriptorBuilder | |||||
| implements DescriptorBuilder | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( ServiceDescriptorBuilder.class ); | |||||
| private static final Version SERVICE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||||
| /** | |||||
| * Builds a descriptor from a set of configuration. | |||||
| */ | |||||
| public TypelibDescriptor createDescriptor( final Configuration config, | |||||
| final String url ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| // Check version | |||||
| final String versionString = config.getAttribute( "version" ); | |||||
| final Version version = Version.getVersion( versionString ); | |||||
| if( !SERVICE_DESCRIPTOR_VERSION.complies( version ) ) | |||||
| { | |||||
| final String message = REZ.getString( "service-descriptor-version.error", | |||||
| version, SERVICE_DESCRIPTOR_VERSION ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| // Build the descriptor | |||||
| final ServiceDescriptor descriptor = new ServiceDescriptor( url ); | |||||
| // Add the service definitions | |||||
| final Configuration[] elements = config.getChildren(); | |||||
| for( int i = 0; i < elements.length; i++ ) | |||||
| { | |||||
| final Configuration element = elements[ i ]; | |||||
| final String roleShorthand = element.getName(); | |||||
| final String factoryClassName = element.getAttribute( "factory" ); | |||||
| final ServiceDefinition definition = | |||||
| new ServiceDefinition( roleShorthand, factoryClassName, config ); | |||||
| descriptor.addDefinition( definition ); | |||||
| } | |||||
| return descriptor; | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "build-service-descriptor.error", url ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,40 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||||
| /** | |||||
| * A typelib type descriptor, which defines a set of types. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class TypeDescriptor | |||||
| extends TypelibDescriptor | |||||
| { | |||||
| private final List m_definitions = new ArrayList(); | |||||
| public TypeDescriptor( final String url ) | |||||
| { | |||||
| super( url ); | |||||
| } | |||||
| public TypeDefinition[] getDefinitions() | |||||
| { | |||||
| return (TypeDefinition[])m_definitions.toArray | |||||
| ( new TypeDefinition[ m_definitions.size() ] ); | |||||
| } | |||||
| public void addDefinition( final TypeDefinition def ) | |||||
| { | |||||
| m_definitions.add( def ); | |||||
| } | |||||
| } | |||||
| @@ -1,96 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.Version; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| import org.apache.myrmidon.interfaces.deployer.ConverterDefinition; | |||||
| import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
| import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||||
| /** | |||||
| * Builds typelib type descriptors. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class TypeDescriptorBuilder | |||||
| implements DescriptorBuilder | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( TypeDescriptorBuilder.class ); | |||||
| private static final Version TYPE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||||
| /** | |||||
| * Builds a descriptor from a set of configuration. | |||||
| */ | |||||
| public TypelibDescriptor createDescriptor( final Configuration config, | |||||
| final String url ) | |||||
| throws DeploymentException | |||||
| { | |||||
| try | |||||
| { | |||||
| // Check version | |||||
| final String versionString = config.getAttribute( "version" ); | |||||
| final Version version = Version.getVersion( versionString ); | |||||
| if( !TYPE_DESCRIPTOR_VERSION.complies( version ) ) | |||||
| { | |||||
| final String message = REZ.getString( "type-descriptor-version.error", | |||||
| version, TYPE_DESCRIPTOR_VERSION ); | |||||
| throw new DeploymentException( message ); | |||||
| } | |||||
| // Assemble the descriptor | |||||
| final TypeDescriptor descriptor = new TypeDescriptor( url ); | |||||
| // Extract each of the types elements | |||||
| final Configuration[] typeEntries = config.getChild( "types" ).getChildren(); | |||||
| for( int i = 0; i < typeEntries.length; i++ ) | |||||
| { | |||||
| final Configuration typeEntry = typeEntries[ i ]; | |||||
| final TypeDefinition typeDef = createTypeDefinition( typeEntry ); | |||||
| descriptor.addDefinition( typeDef ); | |||||
| } | |||||
| return descriptor; | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "build-type-descriptor.error", url ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a type definition. | |||||
| */ | |||||
| private TypeDefinition createTypeDefinition( final Configuration configuration ) | |||||
| throws ConfigurationException | |||||
| { | |||||
| final String roleShorthand = configuration.getName(); | |||||
| if( roleShorthand.equals( "converter" ) ) | |||||
| { | |||||
| // A converter definition | |||||
| final String className = configuration.getAttribute( "classname" ); | |||||
| final String source = configuration.getAttribute( "source" ); | |||||
| final String destination = configuration.getAttribute( "destination" ); | |||||
| return new ConverterDefinition( className, source, destination ); | |||||
| } | |||||
| else | |||||
| { | |||||
| // A type definition | |||||
| final String typeName = configuration.getAttribute( "name" ); | |||||
| final String className = configuration.getAttribute( "classname" ); | |||||
| return new TypeDefinition( typeName, roleShorthand, className ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,32 +0,0 @@ | |||||
| /* | |||||
| * 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.components.deployer; | |||||
| /** | |||||
| * A descriptor from a typelib. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class TypelibDescriptor | |||||
| { | |||||
| private final String m_url; | |||||
| protected TypelibDescriptor( final String url ) | |||||
| { | |||||
| m_url = url; | |||||
| } | |||||
| /** | |||||
| * Returns the descriptor URL. | |||||
| */ | |||||
| public String getUrl() | |||||
| { | |||||
| return m_url; | |||||
| } | |||||
| } | |||||
| @@ -1,454 +0,0 @@ | |||||
| /* | |||||
| * 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.components.embeddor; | |||||
| import java.io.File; | |||||
| import java.io.FilenameFilter; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Iterator; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import org.apache.aut.converter.Converter; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.excalibur.io.ExtensionFileFilter; | |||||
| import org.apache.avalon.excalibur.io.FileUtil; | |||||
| import org.apache.avalon.framework.CascadingException; | |||||
| import org.apache.avalon.framework.context.Contextualizable; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.avalon.framework.context.ContextException; | |||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.activity.Initializable; | |||||
| import org.apache.avalon.framework.activity.Startable; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.parameters.Parameterizable; | |||||
| import org.apache.avalon.framework.parameters.Parameters; | |||||
| import org.apache.avalon.framework.service.DefaultServiceManager; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||||
| import org.apache.myrmidon.interfaces.builder.ProjectBuilder; | |||||
| import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||||
| import org.apache.myrmidon.interfaces.configurer.Configurer; | |||||
| 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.embeddor.Embeddor; | |||||
| import org.apache.myrmidon.interfaces.executor.Executor; | |||||
| import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
| import org.apache.myrmidon.interfaces.executor.ExecutionContainer; | |||||
| import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||||
| import org.apache.myrmidon.interfaces.model.Project; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
| import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| import org.apache.myrmidon.interfaces.service.MultiSourceServiceManager; | |||||
| import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| import org.apache.myrmidon.interfaces.workspace.Workspace; | |||||
| import org.apache.myrmidon.listeners.ProjectListener; | |||||
| import org.apache.myrmidon.components.workspace.DefaultExecutionFrame; | |||||
| import org.apache.myrmidon.components.store.DefaultPropertyStore; | |||||
| /** | |||||
| * Default implementation of Embeddor. | |||||
| * Instantiate this to embed inside other applications. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultEmbeddor | |||||
| extends AbstractLogEnabled | |||||
| implements Embeddor, Contextualizable, Initializable, Startable, Disposable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultEmbeddor.class ); | |||||
| /** Package containing the default component implementations. */ | |||||
| private static final String PREFIX = "org.apache.myrmidon.components."; | |||||
| private Deployer m_deployer; | |||||
| private TypeManager m_typeManager; | |||||
| private MultiSourceServiceManager m_workspaceServiceManager; | |||||
| private List m_components = new ArrayList(); | |||||
| private DefaultServiceManager m_serviceManager = new DefaultServiceManager(); | |||||
| private Context m_context; | |||||
| /** | |||||
| * Setup basic properties of engine. | |||||
| * Called before init() and can be used to specify alternate components in system. | |||||
| */ | |||||
| public void contextualize( final Context context ) throws ContextException | |||||
| { | |||||
| m_context = context; | |||||
| } | |||||
| /** | |||||
| * Builds a project. | |||||
| */ | |||||
| public Project createProject( final String location, | |||||
| final String type, | |||||
| final Parameters parameters ) | |||||
| throws Exception | |||||
| { | |||||
| try | |||||
| { | |||||
| String projectType = type; | |||||
| if( null == projectType ) | |||||
| { | |||||
| projectType = FileUtil.getExtension( location ); | |||||
| } | |||||
| // TODO - reuse the project builders, or dispose them | |||||
| final ProjectBuilder builder = getProjectBuilder( projectType, parameters ); | |||||
| return builder.build( location ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "create-project.error", location ); | |||||
| throw new CascadingException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a project builder for a project type. | |||||
| */ | |||||
| private ProjectBuilder getProjectBuilder( final String type, | |||||
| final Parameters parameters ) | |||||
| throws Exception | |||||
| { | |||||
| final TypeFactory factory = m_typeManager.getFactory( ProjectBuilder.ROLE ); | |||||
| final ProjectBuilder builder = (ProjectBuilder)factory.create( type ); | |||||
| setupObject( builder, m_serviceManager, parameters ); | |||||
| return builder; | |||||
| } | |||||
| /** | |||||
| * Creates a workspace. | |||||
| */ | |||||
| public Workspace createWorkspace( final Map properties ) | |||||
| throws Exception | |||||
| { | |||||
| final Workspace workspace = | |||||
| (Workspace)createService( Workspace.class, PREFIX + "workspace.DefaultWorkspace" ); | |||||
| setupObject( workspace, m_workspaceServiceManager, null ); | |||||
| // Create the property store | |||||
| final PropertyStore propStore = createBaseStore( properties ); | |||||
| // Create an execution frame, and attach it to the workspace | |||||
| final ExecutionFrame frame = | |||||
| new DefaultExecutionFrame( getLogger(), | |||||
| propStore, | |||||
| m_workspaceServiceManager); | |||||
| ( (ExecutionContainer)workspace ).setRootExecutionFrame( frame ); | |||||
| // TODO - should keep track of workspaces, to dispose them later | |||||
| return workspace; | |||||
| } | |||||
| /** | |||||
| * Creates a project listener. | |||||
| * | |||||
| * @param name The shorthand name of the listener. | |||||
| * @return the listener. | |||||
| */ | |||||
| public ProjectListener createListener( final String name ) | |||||
| throws Exception | |||||
| { | |||||
| final TypeFactory factory = m_typeManager.getFactory( ProjectListener.ROLE ); | |||||
| return (ProjectListener)factory.create( name ); | |||||
| } | |||||
| /** | |||||
| * Initialize the system. | |||||
| * | |||||
| * @exception Exception if an error occurs | |||||
| */ | |||||
| public void initialize() | |||||
| throws Exception | |||||
| { | |||||
| // setup the root components | |||||
| setupComponents(); | |||||
| // locate the components we need | |||||
| m_deployer = (Deployer)m_serviceManager.lookup( Deployer.ROLE ); | |||||
| m_typeManager = (TypeManager)m_serviceManager.lookup( TypeManager.ROLE ); | |||||
| // setup a service manager that creates the project services | |||||
| final ServiceManager projServiceManager | |||||
| = (ServiceManager)createService( ServiceManager.class, | |||||
| PREFIX + "service.InstantiatingServiceManager" ); | |||||
| setupObject( projServiceManager, m_serviceManager, null ); | |||||
| m_components.add( projServiceManager ); | |||||
| // setup a service manager to be used by workspaces | |||||
| m_workspaceServiceManager = new MultiSourceServiceManager(); | |||||
| m_workspaceServiceManager.add( projServiceManager ); | |||||
| m_workspaceServiceManager.add( m_serviceManager ); | |||||
| } | |||||
| public void start() | |||||
| throws Exception | |||||
| { | |||||
| // Deploy all type libraries found in the classpath | |||||
| final ClassLoader libClassloader = getClass().getClassLoader(); | |||||
| final TypeDeployer typeDeployer = m_deployer.createDeployer( libClassloader ); | |||||
| typeDeployer.deployAll(); | |||||
| // Deploy all type libraries in the lib directory | |||||
| final ExtensionFileFilter filter = new ExtensionFileFilter( ".atl" ); | |||||
| final File[] taskLibDirs = (File[])m_context.get( "myrmidon.lib.path" ); | |||||
| deployFromDirectories( m_deployer, taskLibDirs, filter ); | |||||
| } | |||||
| /** | |||||
| * Stops the engine. | |||||
| */ | |||||
| public void stop() | |||||
| { | |||||
| //TODO - Undeploy all the tasks by killing ExecutionFrame??? | |||||
| } | |||||
| /** | |||||
| * Dispose engine. | |||||
| */ | |||||
| public void dispose() | |||||
| { | |||||
| // Dispose any disposable components | |||||
| for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | |||||
| { | |||||
| Object component = iterator.next(); | |||||
| if( component instanceof Disposable ) | |||||
| { | |||||
| final Disposable disposable = (Disposable)component; | |||||
| disposable.dispose(); | |||||
| } | |||||
| } | |||||
| // Ditch everything | |||||
| m_components = null; | |||||
| m_deployer = null; | |||||
| m_serviceManager = null; | |||||
| m_context = null; | |||||
| } | |||||
| /** | |||||
| * Create all required components. | |||||
| */ | |||||
| private void setupComponents() | |||||
| throws Exception | |||||
| { | |||||
| // Create the components | |||||
| createComponent( ExtensionManager.class, PREFIX + "extensions.DefaultExtensionManager" ); | |||||
| final Object converter = | |||||
| createComponent( Converter.class, PREFIX + "converter.DefaultMasterConverter" ); | |||||
| m_serviceManager.put( ConverterRegistry.ROLE, converter ); | |||||
| createComponent( Configurer.class, PREFIX + "configurer.DefaultConfigurer" ); | |||||
| createComponent( TypeManager.class, PREFIX + "type.DefaultTypeManager" ); | |||||
| createComponent( RoleManager.class, PREFIX + "role.DefaultRoleManager" ); | |||||
| createComponent( AspectManager.class, PREFIX + "aspect.DefaultAspectManager" ); | |||||
| createComponent( Deployer.class, PREFIX + "deployer.DefaultDeployer" ); | |||||
| createComponent( ClassLoaderManager.class, | |||||
| PREFIX + "classloader.DefaultClassLoaderManager" ); | |||||
| createComponent( Executor.class, PREFIX + "executor.AspectAwareExecutor" ); | |||||
| createComponent( PropertyResolver.class, PREFIX + "property.DefaultPropertyResolver" ); | |||||
| m_serviceManager.put( Embeddor.ROLE, this ); | |||||
| // Setup the components | |||||
| for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | |||||
| { | |||||
| final Object component = iterator.next(); | |||||
| setupObject( component, m_serviceManager, null ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a component. | |||||
| */ | |||||
| private Object createComponent( final Class roleType, | |||||
| final String defaultImpl ) | |||||
| throws Exception | |||||
| { | |||||
| final Object component = createService( roleType, defaultImpl ); | |||||
| m_serviceManager.put( roleType.getName(), component ); | |||||
| m_components.add( component ); | |||||
| return component; | |||||
| } | |||||
| /** | |||||
| * Create a component that implements an interface. | |||||
| * | |||||
| * @param roleType the name of interface/type | |||||
| * @param defaultImpl the classname of the default implementation | |||||
| * @return the created object | |||||
| * @exception Exception if an error occurs | |||||
| */ | |||||
| private Object createService( final Class roleType, final String defaultImpl ) | |||||
| throws Exception | |||||
| { | |||||
| // TODO - need to be able to provide different implementations | |||||
| final String className = defaultImpl; | |||||
| try | |||||
| { | |||||
| final Object object = Class.forName( className ).newInstance(); | |||||
| if( !roleType.isInstance( object ) ) | |||||
| { | |||||
| final String message = REZ.getString( "bad-type.error", | |||||
| className, roleType.getName() ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| return object; | |||||
| } | |||||
| catch( final IllegalAccessException iae ) | |||||
| { | |||||
| final String message = REZ.getString( "bad-ctor.error", | |||||
| roleType.getName(), className ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| catch( final InstantiationException ie ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "no-instantiate.error", roleType.getName(), className ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| catch( final ClassNotFoundException cnfe ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "no-class.error", roleType.getName(), className ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Sets-up an object by running it through the log-enable, compose, | |||||
| * parameterise and initialise lifecycle stages. | |||||
| */ | |||||
| private void setupObject( final Object object, | |||||
| final ServiceManager serviceManager, | |||||
| final Parameters parameters ) | |||||
| throws Exception | |||||
| { | |||||
| setupLogger( object ); | |||||
| if(object instanceof Contextualizable ) | |||||
| { | |||||
| ( (Contextualizable)object ).contextualize( m_context ); | |||||
| } | |||||
| if( object instanceof Serviceable ) | |||||
| { | |||||
| ( (Serviceable)object ).service( serviceManager ); | |||||
| } | |||||
| if( parameters != null && object instanceof Parameterizable ) | |||||
| { | |||||
| ( (Parameterizable)object ).parameterize( parameters ); | |||||
| } | |||||
| if( object instanceof Initializable ) | |||||
| { | |||||
| ( (Initializable)object ).initialize(); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Deploys all type libraries in a directory. | |||||
| */ | |||||
| private void deployFromDirectories( final Deployer deployer, | |||||
| final File[] directories, | |||||
| final FilenameFilter filter ) | |||||
| throws DeploymentException | |||||
| { | |||||
| for( int i = 0; i < directories.length; i++ ) | |||||
| { | |||||
| File directory = directories[i ]; | |||||
| final File[] files = directory.listFiles( filter ); | |||||
| if( null != files ) | |||||
| { | |||||
| deployFiles( deployer, files ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Deploys a set of type libraries. | |||||
| */ | |||||
| private void deployFiles( final Deployer deployer, final File[] files ) | |||||
| throws DeploymentException | |||||
| { | |||||
| for( int i = 0; i < files.length; i++ ) | |||||
| { | |||||
| final String filename = files[ i ].getName(); | |||||
| int index = filename.lastIndexOf( '.' ); | |||||
| if( -1 == index ) | |||||
| { | |||||
| index = filename.length(); | |||||
| } | |||||
| try | |||||
| { | |||||
| final File file = files[ i ].getCanonicalFile(); | |||||
| final TypeDeployer typeDeployer = deployer.createDeployer( file ); | |||||
| typeDeployer.deployAll(); | |||||
| } | |||||
| catch( final DeploymentException de ) | |||||
| { | |||||
| throw de; | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "bad-filename.error", files[ i ] ); | |||||
| throw new DeploymentException( message, e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates the root property store for a workspace | |||||
| */ | |||||
| private PropertyStore createBaseStore( final Map properties ) | |||||
| throws Exception | |||||
| { | |||||
| final DefaultPropertyStore store = new DefaultPropertyStore(); | |||||
| addToStore( store, properties ); | |||||
| //Add system properties so that they overide user-defined properties | |||||
| addToStore( store, System.getProperties() ); | |||||
| return store; | |||||
| } | |||||
| /** | |||||
| * Helper method to add values to a store. | |||||
| * | |||||
| * @param store the store | |||||
| * @param map the map of names->values | |||||
| */ | |||||
| private void addToStore( final PropertyStore store, final Map map ) | |||||
| throws Exception | |||||
| { | |||||
| final Iterator keys = map.keySet().iterator(); | |||||
| while( keys.hasNext() ) | |||||
| { | |||||
| final String key = (String)keys.next(); | |||||
| final Object value = map.get( key ); | |||||
| store.setProperty( key, value ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,6 +0,0 @@ | |||||
| bad-type.error=Object {0} is not an instance of {1}. | |||||
| bad-ctor.error=Non-public constructor for {0} {1}. | |||||
| no-instantiate.error=Error instantiating class for {0} {1}. | |||||
| no-class.error=Could not find the class for {0} ({1}). | |||||
| bad-filename.error=Unable to retrieve filename for file {0}. | |||||
| create-project.error=Could not load the project definition from {0}. | |||||
| @@ -1,337 +0,0 @@ | |||||
| /* | |||||
| * 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.components.executor; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| import org.apache.avalon.framework.configuration.DefaultConfiguration; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| import org.apache.avalon.framework.parameters.Parameters; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.api.Task; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||||
| import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
| /** | |||||
| * The AspectAwareExecutor executes the tasks but also calls | |||||
| * the aspects helpers. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class AspectAwareExecutor | |||||
| extends DefaultExecutor | |||||
| implements Serviceable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( AspectAwareExecutor.class ); | |||||
| private static final Configuration[] EMPTY_ELEMENTS = new Configuration[ 0 ]; | |||||
| private AspectManager m_aspectManager; | |||||
| /** | |||||
| * Retrieve relevent services. | |||||
| * | |||||
| * @param serviceManager the ServiceManager | |||||
| * @exception ServiceException if an error occurs | |||||
| */ | |||||
| public void service( final ServiceManager serviceManager ) | |||||
| throws ServiceException | |||||
| { | |||||
| m_aspectManager = (AspectManager)serviceManager.lookup( AspectManager.ROLE ); | |||||
| } | |||||
| public void execute( final Configuration taskModel, final ExecutionFrame frame ) | |||||
| throws TaskException | |||||
| { | |||||
| try | |||||
| { | |||||
| executeTask( taskModel, frame ); | |||||
| } | |||||
| catch( final TaskException te ) | |||||
| { | |||||
| final boolean isError = getAspectManager().error( te ); | |||||
| if( !isError ) | |||||
| { | |||||
| throw te; | |||||
| } | |||||
| } | |||||
| } | |||||
| private void executeTask( final Configuration model, | |||||
| final ExecutionFrame frame ) | |||||
| throws TaskException | |||||
| { | |||||
| try | |||||
| { | |||||
| Configuration taskModel = getAspectManager().preCreate( model ); | |||||
| taskModel = prepareAspects( taskModel ); | |||||
| final String taskName = taskModel.getName(); | |||||
| debug( "creating.notice", taskName ); | |||||
| final Task task = doCreateTask( taskName, frame ); | |||||
| getAspectManager().postCreate( task ); | |||||
| debug( "logger.notice", taskName ); | |||||
| final Logger logger = frame.getLogger(); | |||||
| getAspectManager().preLogEnabled( logger ); | |||||
| debug( "contextualizing.notice", taskName ); | |||||
| final TaskContext context = doCreateContext( frame ); | |||||
| doContextualize( task, taskModel, context, frame ); | |||||
| debug( "configuring.notice", taskName ); | |||||
| getAspectManager().preConfigure( taskModel ); | |||||
| doConfigure( task, taskModel, context, frame ); | |||||
| debug( "executing.notice", taskName ); | |||||
| getAspectManager().preExecute(); | |||||
| doExecute( taskModel, task ); | |||||
| getAspectManager().preDestroy(); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| // Wrap in generic error message | |||||
| final String message = REZ.getString( "execute.error", | |||||
| model.getName(), | |||||
| model.getLocation() ); | |||||
| throw new TaskException( message, e ); | |||||
| } | |||||
| } | |||||
| protected void doExecute( final Configuration taskModel, final Task task ) | |||||
| throws TaskException | |||||
| { | |||||
| task.execute(); | |||||
| } | |||||
| //TODO: Extract and clean taskModel here. | |||||
| //Get all parameters from model and provide to appropriate aspect. | |||||
| //aspect( final Parameters parameters, final Configuration[] elements ) | |||||
| private final Configuration prepareAspects( final Configuration taskModel ) | |||||
| throws TaskException | |||||
| { | |||||
| final DefaultConfiguration newTaskModel = | |||||
| new DefaultConfiguration( taskModel.getName(), taskModel.getLocation() ); | |||||
| final HashMap parameterMap = new HashMap(); | |||||
| final HashMap elementMap = new HashMap(); | |||||
| processAttributes( taskModel, newTaskModel, parameterMap ); | |||||
| processElements( taskModel, newTaskModel, elementMap ); | |||||
| try | |||||
| { | |||||
| newTaskModel.setValue( taskModel.getValue() ); | |||||
| } | |||||
| catch( final ConfigurationException cee ) | |||||
| { | |||||
| //Will never occur | |||||
| } | |||||
| dispatchAspectsSettings( parameterMap, elementMap ); | |||||
| checkForUnusedSettings( parameterMap, elementMap ); | |||||
| return newTaskModel; | |||||
| } | |||||
| private final void dispatchAspectsSettings( final HashMap parameterMap, | |||||
| final HashMap elementMap ) | |||||
| throws TaskException | |||||
| { | |||||
| final String[] names = getAspectManager().getNames(); | |||||
| for( int i = 0; i < names.length; i++ ) | |||||
| { | |||||
| final ArrayList elementList = (ArrayList)elementMap.remove( names[ i ] ); | |||||
| Parameters parameters = (Parameters)parameterMap.remove( names[ i ] ); | |||||
| if( null == parameters ) | |||||
| { | |||||
| parameters = Parameters.EMPTY_PARAMETERS; | |||||
| } | |||||
| Configuration[] elements = null; | |||||
| if( null == elementList ) | |||||
| { | |||||
| elements = EMPTY_ELEMENTS; | |||||
| } | |||||
| else | |||||
| { | |||||
| elements = (Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||||
| } | |||||
| dispatch( names[ i ], parameters, elements ); | |||||
| } | |||||
| } | |||||
| private final void checkForUnusedSettings( final HashMap parameterMap, | |||||
| final HashMap elementMap ) | |||||
| throws TaskException | |||||
| { | |||||
| if( 0 != parameterMap.size() ) | |||||
| { | |||||
| final String[] namespaces = | |||||
| (String[])parameterMap.keySet().toArray( new String[ 0 ] ); | |||||
| for( int i = 0; i < namespaces.length; i++ ) | |||||
| { | |||||
| final String namespace = namespaces[ i ]; | |||||
| final Parameters parameters = (Parameters)parameterMap.get( namespace ); | |||||
| final ArrayList elementList = (ArrayList)elementMap.remove( namespace ); | |||||
| Configuration[] elements = null; | |||||
| if( null == elementList ) | |||||
| { | |||||
| elements = EMPTY_ELEMENTS; | |||||
| } | |||||
| else | |||||
| { | |||||
| elements = (Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||||
| } | |||||
| unusedSetting( namespace, parameters, elements ); | |||||
| } | |||||
| } | |||||
| if( 0 != elementMap.size() ) | |||||
| { | |||||
| final String[] namespaces = | |||||
| (String[])elementMap.keySet().toArray( new String[ 0 ] ); | |||||
| for( int i = 0; i < namespaces.length; i++ ) | |||||
| { | |||||
| final String namespace = namespaces[ i ]; | |||||
| final ArrayList elementList = (ArrayList)elementMap.remove( namespace ); | |||||
| final Configuration[] elements = | |||||
| (Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||||
| unusedSetting( namespace, Parameters.EMPTY_PARAMETERS, elements ); | |||||
| } | |||||
| } | |||||
| } | |||||
| private void unusedSetting( final String namespace, | |||||
| final Parameters parameters, | |||||
| final Configuration[] elements ) | |||||
| throws TaskException | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "unused-settings.error", | |||||
| namespace, | |||||
| Integer.toString( parameters.getNames().length ), | |||||
| Integer.toString( elements.length ) ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| private void dispatch( final String namespace, | |||||
| final Parameters parameters, | |||||
| final Configuration[] elements ) | |||||
| throws TaskException | |||||
| { | |||||
| getAspectManager().dispatchAspectSettings( namespace, parameters, elements ); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "dispatch-settings.notice", | |||||
| namespace, | |||||
| Integer.toString( parameters.getNames().length ), | |||||
| Integer.toString( elements.length ) ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| } | |||||
| private final void processElements( final Configuration taskModel, | |||||
| final DefaultConfiguration newTaskModel, | |||||
| final HashMap map ) | |||||
| { | |||||
| final Configuration[] elements = taskModel.getChildren(); | |||||
| for( int i = 0; i < elements.length; i++ ) | |||||
| { | |||||
| final String name = elements[ i ].getName(); | |||||
| final int index = name.indexOf( ':' ); | |||||
| if( -1 == index ) | |||||
| { | |||||
| newTaskModel.addChild( elements[ i ] ); | |||||
| } | |||||
| else | |||||
| { | |||||
| final String namespace = name.substring( 0, index ); | |||||
| final ArrayList elementSet = getElements( namespace, map ); | |||||
| elementSet.add( elements[ i ] ); | |||||
| } | |||||
| } | |||||
| } | |||||
| private final void processAttributes( final Configuration taskModel, | |||||
| final DefaultConfiguration newTaskModel, | |||||
| final HashMap map ) | |||||
| { | |||||
| final String[] attributes = taskModel.getAttributeNames(); | |||||
| for( int i = 0; i < attributes.length; i++ ) | |||||
| { | |||||
| final String name = attributes[ i ]; | |||||
| final String value = taskModel.getAttribute( name, null ); | |||||
| final int index = name.indexOf( ':' ); | |||||
| if( -1 == index ) | |||||
| { | |||||
| newTaskModel.setAttribute( name, value ); | |||||
| } | |||||
| else | |||||
| { | |||||
| final String namespace = name.substring( 0, index ); | |||||
| final String localName = name.substring( index + 1 ); | |||||
| final Parameters parameters = getParameters( namespace, map ); | |||||
| parameters.setParameter( localName, value ); | |||||
| } | |||||
| } | |||||
| } | |||||
| private final ArrayList getElements( final String namespace, final HashMap map ) | |||||
| { | |||||
| ArrayList elements = (ArrayList)map.get( namespace ); | |||||
| if( null == elements ) | |||||
| { | |||||
| elements = new ArrayList(); | |||||
| map.put( namespace, elements ); | |||||
| } | |||||
| return elements; | |||||
| } | |||||
| private final Parameters getParameters( final String namespace, final HashMap map ) | |||||
| { | |||||
| Parameters parameters = (Parameters)map.get( namespace ); | |||||
| if( null == parameters ) | |||||
| { | |||||
| parameters = new Parameters(); | |||||
| map.put( namespace, parameters ); | |||||
| } | |||||
| return parameters; | |||||
| } | |||||
| private final AspectManager getAspectManager() | |||||
| { | |||||
| return m_aspectManager; | |||||
| } | |||||
| } | |||||
| @@ -1,141 +0,0 @@ | |||||
| /* | |||||
| * 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.components.executor; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.myrmidon.api.Task; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.components.workspace.DefaultTaskContext; | |||||
| import org.apache.myrmidon.interfaces.configurer.Configurer; | |||||
| import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
| import org.apache.myrmidon.interfaces.executor.Executor; | |||||
| import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| /** | |||||
| * The basic executor that just executes the tasks. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultExecutor | |||||
| extends AbstractLogEnabled | |||||
| implements Executor | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultExecutor.class ); | |||||
| /** | |||||
| * Executes a task. | |||||
| */ | |||||
| public void execute( final Configuration taskModel, final ExecutionFrame frame ) | |||||
| throws TaskException | |||||
| { | |||||
| final String taskName = taskModel.getName(); | |||||
| try | |||||
| { | |||||
| debug( "creating.notice", taskName ); | |||||
| final Task task = doCreateTask( taskName, frame ); | |||||
| debug( "contextualizing.notice", taskName ); | |||||
| final TaskContext context = doCreateContext( frame ); | |||||
| doContextualize( task, taskModel, context, frame ); | |||||
| debug( "configuring.notice", taskName ); | |||||
| doConfigure( task, taskModel, context, frame ); | |||||
| debug( "executing.notice", taskName ); | |||||
| task.execute(); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| // Wrap in generic error message | |||||
| final String message = REZ.getString( "execute.error", | |||||
| taskName, taskModel.getLocation() ); | |||||
| throw new TaskException( message, e ); | |||||
| } | |||||
| } | |||||
| protected final void debug( final String key, final String taskName ) | |||||
| { | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( key, taskName ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a context for the task. | |||||
| */ | |||||
| protected TaskContext doCreateContext( final ExecutionFrame frame ) | |||||
| { | |||||
| // TODO - need to deactivate the context once the task has finished | |||||
| // executing | |||||
| return new DefaultTaskContext( frame.getServiceManager(), | |||||
| frame.getLogger(), | |||||
| frame.getProperties() ); | |||||
| } | |||||
| /** | |||||
| * Creates a task instance. | |||||
| */ | |||||
| protected final Task doCreateTask( final String name, final ExecutionFrame frame ) | |||||
| throws TaskException | |||||
| { | |||||
| try | |||||
| { | |||||
| final TypeManager typeManager = (TypeManager)frame.getServiceManager().lookup( TypeManager.ROLE ); | |||||
| final TypeFactory factory = typeManager.getFactory( Task.ROLE ); | |||||
| return (Task)factory.create( name ); | |||||
| } | |||||
| catch( final Exception te ) | |||||
| { | |||||
| final String message = REZ.getString( "create.error", name ); | |||||
| throw new TaskException( message, te ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Configures a task instance. | |||||
| */ | |||||
| protected final void doConfigure( final Task task, | |||||
| final Configuration taskModel, | |||||
| final TaskContext taskContext, | |||||
| final ExecutionFrame frame ) | |||||
| throws Exception | |||||
| { | |||||
| final Configurer configurer = (Configurer)frame.getServiceManager().lookup( Configurer.ROLE ); | |||||
| configurer.configureElement( task, taskModel, taskContext ); | |||||
| } | |||||
| /** | |||||
| * Sets the context for a task. | |||||
| */ | |||||
| protected final void doContextualize( final Task task, | |||||
| final Configuration taskModel, | |||||
| final TaskContext taskContext, | |||||
| final ExecutionFrame frame ) | |||||
| throws TaskException | |||||
| { | |||||
| try | |||||
| { | |||||
| task.contextualize( taskContext ); | |||||
| } | |||||
| catch( final Throwable throwable ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "contextualize.error", taskModel.getName() ); | |||||
| throw new TaskException( message, throwable ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,81 +0,0 @@ | |||||
| /* | |||||
| * 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.components.executor; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.myrmidon.api.Task; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| /** | |||||
| * An executor that just displays the tasks rather than executing them. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class PrintingExecutor | |||||
| extends AspectAwareExecutor | |||||
| { | |||||
| protected void doExecute( final Configuration taskModel, final Task task ) | |||||
| throws TaskException | |||||
| { | |||||
| final StringBuffer sb = new StringBuffer(); | |||||
| printConfiguration( taskModel, 0, sb ); | |||||
| System.out.println( sb.toString() ); | |||||
| } | |||||
| private void printConfiguration( final Configuration taskModel, | |||||
| final int level, | |||||
| final StringBuffer sb ) | |||||
| { | |||||
| for( int i = 0; i < level; i++ ) | |||||
| { | |||||
| sb.append( ' ' ); | |||||
| } | |||||
| sb.append( '<' ); | |||||
| sb.append( taskModel.getName() ); | |||||
| final String[] names = taskModel.getAttributeNames(); | |||||
| for( int i = 0; i < names.length; i++ ) | |||||
| { | |||||
| final String name = names[ i ]; | |||||
| final String value = taskModel.getAttribute( name, null ); | |||||
| sb.append( ' ' ); | |||||
| sb.append( name ); | |||||
| sb.append( "=\"" ); | |||||
| sb.append( value ); | |||||
| sb.append( '\"' ); | |||||
| } | |||||
| final Configuration[] children = taskModel.getChildren(); | |||||
| if( 0 == children.length ) | |||||
| { | |||||
| sb.append( "/>\n" ); | |||||
| } | |||||
| else | |||||
| { | |||||
| sb.append( ">\n" ); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | |||||
| printConfiguration( children[ i ], level + 1, sb ); | |||||
| } | |||||
| for( int i = 0; i < level; i++ ) | |||||
| { | |||||
| sb.append( ' ' ); | |||||
| } | |||||
| sb.append( "</" ); | |||||
| sb.append( taskModel.getName() ); | |||||
| sb.append( ">\n" ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,11 +0,0 @@ | |||||
| creating.notice=Creating {0}. | |||||
| contextualizing.notice=Contextualizing {0}. | |||||
| configuring.notice=Configuring {0}. | |||||
| executing.notice=Executing {0}. | |||||
| create.error=Could not create task <{0}>. | |||||
| contextualize.error=Could not set the context for task <{0}>. | |||||
| execute.error={1}: Could not execute task <{0}>. | |||||
| unused-settings.error=Unused aspect settings for namespace {0} (parameterCount={1} elementCount={2}). | |||||
| dispatch-settings.notice=Dispatching Aspect Settings to namespace {0} (parameterCount={1} elementCount={2}). | |||||
| @@ -1,162 +0,0 @@ | |||||
| /* | |||||
| * 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.components.extensions; | |||||
| import java.io.File; | |||||
| import org.apache.avalon.excalibur.extension.DefaultPackageRepository; | |||||
| import org.apache.avalon.excalibur.extension.Extension; | |||||
| import org.apache.avalon.excalibur.extension.OptionalPackage; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.activity.Initializable; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.avalon.framework.context.ContextException; | |||||
| import org.apache.avalon.framework.context.Contextualizable; | |||||
| import org.apache.avalon.framework.logger.LogEnabled; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||||
| /** | |||||
| * PhoenixPackageRepository | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultExtensionManager | |||||
| extends DefaultPackageRepository | |||||
| implements LogEnabled, Contextualizable, Initializable, Disposable, ExtensionManager | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultExtensionManager.class ); | |||||
| /** | |||||
| * The standard location of tools.jar for IBM/Sun JDKs. | |||||
| */ | |||||
| private static final String TOOLS_JAR = | |||||
| File.separator + "lib" + File.separator + "tools.jar"; | |||||
| /** | |||||
| * The path relative to JRE in which tools.jar is located. | |||||
| */ | |||||
| private static final String DEBIAN_TOOLS_JAR = | |||||
| File.separator + ".." + File.separator + "j2sdk1.3" + | |||||
| File.separator + "lib" + File.separator + "tools.jar"; | |||||
| private Logger m_logger; | |||||
| private File[] m_path; | |||||
| public DefaultExtensionManager() | |||||
| { | |||||
| super( new File[ 0 ] ); | |||||
| } | |||||
| public DefaultExtensionManager( final File[] path ) | |||||
| { | |||||
| super( path ); | |||||
| } | |||||
| public void enableLogging( final Logger logger ) | |||||
| { | |||||
| m_logger = logger; | |||||
| } | |||||
| public void contextualize( final Context context ) throws ContextException | |||||
| { | |||||
| m_path = (File[])context.get( "myrmidon.ext.path" ); | |||||
| } | |||||
| public void initialize() | |||||
| throws Exception | |||||
| { | |||||
| setPath( m_path ); | |||||
| scanPath(); | |||||
| // Add the JVM's tools.jar as an extension | |||||
| final Extension extension = createToolsExtension(); | |||||
| final File jar = getToolsJar(); | |||||
| final Extension[] available = new Extension[]{extension}; | |||||
| final Extension[] required = new Extension[ 0 ]; | |||||
| final OptionalPackage toolsPackage = new OptionalPackage( jar, available, required ); | |||||
| cacheOptionalPackage( toolsPackage ); | |||||
| } | |||||
| public void dispose() | |||||
| { | |||||
| clearCache(); | |||||
| } | |||||
| /** | |||||
| * Locates the optional package which best matches a required extension. | |||||
| * | |||||
| * @param extension the extension to locate an optional package | |||||
| * @return the optional package, or null if not found. | |||||
| */ | |||||
| public OptionalPackage getOptionalPackage( final Extension extension ) | |||||
| { | |||||
| final OptionalPackage[] packages = getOptionalPackages( extension ); | |||||
| if( null == packages || 0 == packages.length ) return null; | |||||
| //TODO: Use heurisitic to find which is best package | |||||
| return packages[ 0 ]; | |||||
| } | |||||
| protected void debug( final String message ) | |||||
| { | |||||
| m_logger.debug( message ); | |||||
| } | |||||
| private File getToolsJar() | |||||
| throws Exception | |||||
| { | |||||
| final String javaHome = System.getProperty( "java.home" ); | |||||
| String jdkHome; | |||||
| if( javaHome.endsWith( "jre" ) ) | |||||
| { | |||||
| jdkHome = javaHome.substring( 0, javaHome.length() - 4 ); | |||||
| } | |||||
| else | |||||
| { | |||||
| jdkHome = javaHome; | |||||
| } | |||||
| //We need to search through a few locations to locate tools.jar | |||||
| File tools = new File( jdkHome + TOOLS_JAR ); | |||||
| if( tools.exists() ) | |||||
| { | |||||
| return tools; | |||||
| } | |||||
| //The path to tools.jar. In some cases $JRE_HOME is not equal to | |||||
| //$JAVA_HOME/jre. For example, on Debian, IBM's j2sdk1.3 .deb puts | |||||
| //the JRE in /usr/lib/j2sdk1.3, and the JDK in /usr/lib/j2re1.3, | |||||
| //tools.jar=${java.home}/../j2sdk1.3/lib/tools.jar | |||||
| tools = new File( jdkHome + DEBIAN_TOOLS_JAR ); | |||||
| if( !tools.exists() ) | |||||
| { | |||||
| final String message = REZ.getString( "extension.missing-tools.error" ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| return tools; | |||||
| } | |||||
| private static Extension createToolsExtension() | |||||
| { | |||||
| return new Extension( "com.sun.tools", | |||||
| "1.0", | |||||
| "com.sun", | |||||
| "1.0", | |||||
| "com.sun", | |||||
| "com.sun", | |||||
| null ); | |||||
| } | |||||
| } | |||||
| @@ -1,49 +0,0 @@ | |||||
| /* | |||||
| * 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.components.property; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| /** | |||||
| * A {@link PropertyResolver} implementation which resolves properties | |||||
| * as per Ant1, ignoring undefined properties. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | |||||
| * @ant.type type="property-resolver" name="classic" | |||||
| */ | |||||
| public class ClassicPropertyResolver | |||||
| extends DefaultPropertyResolver | |||||
| implements PropertyResolver | |||||
| { | |||||
| /** | |||||
| * Retrieve a value from the specified context using the specified key. | |||||
| * If there is no such value, returns the original property reference. | |||||
| * | |||||
| * @param propertyName the name of the property to retrieve | |||||
| * @param context the set of known properties | |||||
| */ | |||||
| protected Object getPropertyValue( final String propertyName, | |||||
| final TaskContext context ) | |||||
| throws TaskException | |||||
| { | |||||
| final Object value = context.getProperty( propertyName ); | |||||
| if( value != null ) | |||||
| { | |||||
| return value; | |||||
| } | |||||
| else | |||||
| { | |||||
| return "${" + propertyName + "}"; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,290 +0,0 @@ | |||||
| /* | |||||
| * 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.components.property; | |||||
| import org.apache.aut.converter.Converter; | |||||
| import org.apache.aut.converter.ConverterException; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
| /** | |||||
| * Base class for PropertyResolver implementations. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | |||||
| * @ant.type type="property-resolver" name="default" | |||||
| */ | |||||
| public class DefaultPropertyResolver | |||||
| implements PropertyResolver, Serviceable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultPropertyResolver.class ); | |||||
| private Converter m_converter; | |||||
| public void service( final ServiceManager serviceManager ) throws ServiceException | |||||
| { | |||||
| m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||||
| } | |||||
| /** | |||||
| * Resolve a string property. This evaluates all property | |||||
| * substitutions based on specified context. | |||||
| * | |||||
| * If the content contains a single property reference, then the property value | |||||
| * <code>Object</code> itself is returned. | |||||
| * Otherwise, a <code>String</code> is returned, comprising the supplied | |||||
| * content, with all property references replaced with the result of | |||||
| * <code>toString()</code> called on the property value. | |||||
| * | |||||
| * @param content the property to resolve | |||||
| * @param context the context in which to resolve property | |||||
| * @return the reolved property | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| public Object resolveProperties( final String content, | |||||
| final TaskContext context ) | |||||
| throws TaskException | |||||
| { | |||||
| int start = findNextProperty( content, 0 ); | |||||
| if( -1 == start ) | |||||
| { | |||||
| return content; | |||||
| } | |||||
| int end = findEnding( content, start ); | |||||
| final int length = content.length(); | |||||
| if( 0 == start && end == ( length - 1 ) ) | |||||
| { | |||||
| return getPropertyValue( content.substring( start + 2, end ), | |||||
| context ); | |||||
| } | |||||
| final StringBuffer sb = new StringBuffer( length * 2 ); | |||||
| int lastPlace = 0; | |||||
| while( true ) | |||||
| { | |||||
| final String propertyValue = | |||||
| getPropertyStringValue( content.substring( start + 2, end ), | |||||
| context ); | |||||
| sb.append( content.substring( lastPlace, start ) ); | |||||
| sb.append( propertyValue ); | |||||
| lastPlace = end + 1; | |||||
| start = findNextProperty( content, lastPlace ); | |||||
| if( -1 == start ) | |||||
| { | |||||
| break; | |||||
| } | |||||
| end = findEnding( content, start ); | |||||
| } | |||||
| sb.append( content.substring( lastPlace, length ) ); | |||||
| return sb.toString(); | |||||
| } | |||||
| /** | |||||
| * Resolve a string property. This recursively evaluates all property | |||||
| * substitutions based on specified context. | |||||
| * | |||||
| * @param content the property to resolve | |||||
| * @param context the context in which to resolve property | |||||
| * @return the reolved property | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| private Object recursiveResolveProperty( final String content, | |||||
| final TaskContext context ) | |||||
| throws TaskException | |||||
| { | |||||
| int start = findNextProperty( content, 0 ); | |||||
| if( -1 == start ) | |||||
| { | |||||
| return content; | |||||
| } | |||||
| int end = findNestedEnding( content, start ); | |||||
| final int length = content.length(); | |||||
| if( 0 == start && end == ( length - 1 ) ) | |||||
| { | |||||
| final String propertyName = content.substring( start + 2, end ); | |||||
| final Object key = recursiveResolveProperty( propertyName, context ); | |||||
| return getPropertyValue( key.toString(), context ); | |||||
| } | |||||
| final StringBuffer sb = new StringBuffer( length * 2 ); | |||||
| int lastPlace = 0; | |||||
| while( true ) | |||||
| { | |||||
| final String propertyName = content.substring( start + 2, end ); | |||||
| final Object key = recursiveResolveProperty( propertyName, context ); | |||||
| final String value = getPropertyStringValue( key.toString(), context ); | |||||
| sb.append( content.substring( lastPlace, start ) ); | |||||
| sb.append( value ); | |||||
| lastPlace = end + 1; | |||||
| start = findNextProperty( content, lastPlace ); | |||||
| if( -1 == start ) | |||||
| { | |||||
| break; | |||||
| } | |||||
| end = findNestedEnding( content, start ); | |||||
| } | |||||
| sb.append( content.substring( lastPlace, length ) ); | |||||
| return sb.toString(); | |||||
| } | |||||
| /** | |||||
| * Finds the next occurrance of the start of a Property identifier. | |||||
| * @param content the String to search | |||||
| * @param currentPosition start location of the search | |||||
| * @return the position of the next occurrence, or <code>-1</code> if none | |||||
| * was found. | |||||
| */ | |||||
| private int findNextProperty( final String content, final int currentPosition ) | |||||
| { | |||||
| //TODO: Check if it is commented out | |||||
| return content.indexOf( "${", currentPosition ); | |||||
| } | |||||
| /** | |||||
| * Finds the next occurrence of the end of a Property identifier. | |||||
| * @param property the String to search | |||||
| * @param currentPosition start location of the search | |||||
| * @return the position of the next occurrence | |||||
| * @throws TaskException if no end was found | |||||
| */ | |||||
| private int findEnding( final String property, final int currentPosition ) | |||||
| throws TaskException | |||||
| { | |||||
| //TODO: Check if it is commented out | |||||
| final int index = property.indexOf( '}', currentPosition ); | |||||
| if( -1 == index ) | |||||
| { | |||||
| final String message = REZ.getString( "prop.mismatched-braces.error" ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| return index; | |||||
| } | |||||
| /** | |||||
| * Finds the end of the property identifier at the currentPosition, | |||||
| * taking into account nested property identifiers. | |||||
| * @param property the String to search | |||||
| * @param currentPosition location of the property | |||||
| * @return the position of the propery ending. | |||||
| * @throws TaskException if the property is not properly ended. | |||||
| */ | |||||
| private int findNestedEnding( final String property, final int currentPosition ) | |||||
| throws TaskException | |||||
| { | |||||
| final int length = property.length(); | |||||
| final int start = currentPosition + 2; | |||||
| int weight = 1; | |||||
| for( int i = start; ( weight > 0 ) && ( i < length ); i++ ) | |||||
| { | |||||
| final char ch = property.charAt( i ); | |||||
| switch( ch ) | |||||
| { | |||||
| case '}': | |||||
| //TODO: Check if it is commented out | |||||
| weight--; | |||||
| if( weight == 0 ) | |||||
| { | |||||
| return i; | |||||
| } | |||||
| break; | |||||
| case '$': | |||||
| { | |||||
| //TODO: Check if it is commented out | |||||
| final int next = i + 1; | |||||
| if( next < length && '{' == property.charAt( next ) ) | |||||
| { | |||||
| weight++; | |||||
| } | |||||
| } | |||||
| break; | |||||
| } | |||||
| } | |||||
| final String message = REZ.getString( "prop.mismatched-braces.error" ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| /** | |||||
| * Returns a property's value, converted to a String. | |||||
| */ | |||||
| private String getPropertyStringValue( final String propertyName, | |||||
| final TaskContext context ) | |||||
| throws TaskException | |||||
| { | |||||
| final Object value = getPropertyValue( propertyName, context ); | |||||
| if( value instanceof String ) | |||||
| { | |||||
| return (String)value; | |||||
| } | |||||
| try | |||||
| { | |||||
| return (String)m_converter.convert( String.class, value, context ); | |||||
| } | |||||
| catch( final ConverterException e ) | |||||
| { | |||||
| throw new TaskException( e.getMessage(), e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Retrieve a value from the specified context using the specified key. | |||||
| * | |||||
| * @param propertyName the key of value in context | |||||
| * @param context the set of known properties | |||||
| * @return the object retrieved from context | |||||
| * @exception TaskException if the property is undefined | |||||
| */ | |||||
| protected Object getPropertyValue( final String propertyName, | |||||
| final TaskContext context ) | |||||
| throws TaskException | |||||
| { | |||||
| final Object value = context.getProperty( propertyName ); | |||||
| if( value != null ) | |||||
| { | |||||
| return value; | |||||
| } | |||||
| final String message = REZ.getString( "prop.missing-value.error", propertyName ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| } | |||||
| @@ -1,3 +0,0 @@ | |||||
| #AbstractPropertyResolver | |||||
| prop.mismatched-braces.error=Malformed property with mismatched }'s. | |||||
| prop.missing-value.error=Unknown property "{0}". | |||||
| @@ -1,163 +0,0 @@ | |||||
| /* | |||||
| * 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.components.role; | |||||
| import java.util.HashMap; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.myrmidon.interfaces.role.RoleException; | |||||
| import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
| import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| /** | |||||
| * Interface to manage roles and mapping to names. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version CVS $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultRoleManager | |||||
| implements RoleManager | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultRoleManager.class ); | |||||
| /** Parent <code>RoleManager</code> for nested resolution */ | |||||
| private final RoleManager m_parent; | |||||
| /** Map from shorthand name -> RoleInfo. */ | |||||
| private final HashMap m_shorthandMap = new HashMap(); | |||||
| /** Map from role name -> RoleInfo. */ | |||||
| private final HashMap m_nameMap = new HashMap(); | |||||
| /** Map from role type -> RoleInfo. */ | |||||
| private final HashMap m_typeMap = new HashMap(); | |||||
| /** | |||||
| * constructor--this RoleManager has no parent. | |||||
| */ | |||||
| public DefaultRoleManager() | |||||
| { | |||||
| this( null ); | |||||
| } | |||||
| /** | |||||
| * Alternate constructor--this RoleManager has the specified | |||||
| * parent. | |||||
| * | |||||
| * @param parent The parent <code>RoleManager</code>. | |||||
| */ | |||||
| public DefaultRoleManager( final RoleManager parent ) | |||||
| { | |||||
| m_parent = parent; | |||||
| } | |||||
| /** | |||||
| * Find role based on shorthand name. | |||||
| * | |||||
| * @param name the shorthand name | |||||
| * @return the role, or null if the role cannot be found. | |||||
| */ | |||||
| public RoleInfo getRoleByShorthandName( final String name ) | |||||
| { | |||||
| final RoleInfo role = (RoleInfo)m_shorthandMap.get( name ); | |||||
| if( null == role && null != m_parent ) | |||||
| { | |||||
| return m_parent.getRoleByShorthandName( name ); | |||||
| } | |||||
| return role; | |||||
| } | |||||
| /** | |||||
| * Find role based on role type. | |||||
| * | |||||
| * @param type the role type. | |||||
| * @return the role, or null if the role cannot be found. | |||||
| */ | |||||
| public RoleInfo getRoleByType( final Class type ) | |||||
| { | |||||
| final RoleInfo role = (RoleInfo)m_typeMap.get( type ); | |||||
| if( null == role && null != m_parent ) | |||||
| { | |||||
| return m_parent.getRoleByType( type ); | |||||
| } | |||||
| return role; | |||||
| } | |||||
| /** | |||||
| * Find role based on name. | |||||
| * | |||||
| * @param name the role name | |||||
| * @return the role, or null if the role cannot be found. | |||||
| */ | |||||
| public RoleInfo getRole( final String name ) | |||||
| { | |||||
| final RoleInfo role = (RoleInfo)m_nameMap.get( name ); | |||||
| if( null == role && null != m_parent ) | |||||
| { | |||||
| return m_parent.getRole( name ); | |||||
| } | |||||
| return role; | |||||
| } | |||||
| /** | |||||
| * Adds a role definition. | |||||
| */ | |||||
| public void addRole( final RoleInfo role ) throws RoleException | |||||
| { | |||||
| // Check for duplicate role names | |||||
| final String roleName = role.getName(); | |||||
| RoleInfo oldRole = (RoleInfo)m_nameMap.get( roleName ); | |||||
| if( null != oldRole && !oldRole.equals( role ) ) | |||||
| { | |||||
| final String message = REZ.getString( "duplicate-role.error", roleName ); | |||||
| throw new RoleException( message ); | |||||
| } | |||||
| // Check for duplicate shorthand names | |||||
| final String shorthand = role.getShorthand(); | |||||
| if( shorthand != null ) | |||||
| { | |||||
| oldRole = (RoleInfo)m_shorthandMap.get( shorthand ); | |||||
| if( null != oldRole && !oldRole.equals( role ) ) | |||||
| { | |||||
| final String message = REZ.getString( "duplicate-shorthand.error", shorthand ); | |||||
| throw new RoleException( message ); | |||||
| } | |||||
| } | |||||
| // Check for duplicate types | |||||
| final Class roleType = role.getType(); | |||||
| if( roleType != null ) | |||||
| { | |||||
| oldRole = (RoleInfo)m_typeMap.get( roleType ); | |||||
| if( null != oldRole && !oldRole.equals( role ) ) | |||||
| { | |||||
| final String message = REZ.getString( "duplicate-type.error", roleType.getName() ); | |||||
| throw new RoleException( message ); | |||||
| } | |||||
| } | |||||
| // Add the role to the maps | |||||
| m_nameMap.put( roleName, role ); | |||||
| if( shorthand != null ) | |||||
| { | |||||
| m_shorthandMap.put( shorthand, role ); | |||||
| } | |||||
| if( roleType != null ) | |||||
| { | |||||
| m_typeMap.put( roleType, role ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,3 +0,0 @@ | |||||
| duplicate-shorthand.error=Duplicate roles with shorthand name "{0}". | |||||
| duplicate-type.error=Duplicate roles with type "{0}". | |||||
| duplicate-role.error=Duplicate roles with name "{0}". | |||||
| @@ -1,248 +0,0 @@ | |||||
| /* | |||||
| * 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.components.service; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import java.util.Iterator; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.activity.Initializable; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.parameters.ParameterException; | |||||
| import org.apache.avalon.framework.parameters.Parameterizable; | |||||
| import org.apache.avalon.framework.parameters.Parameters; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.avalon.framework.context.Contextualizable; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.avalon.framework.context.ContextException; | |||||
| import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
| import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||||
| import org.apache.myrmidon.interfaces.type.TypeException; | |||||
| import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| /** | |||||
| * A service manager implementation, which creates service instances on demand. | |||||
| * | |||||
| * <p>This manager creates service instances, using a {@link ServiceFactory}, | |||||
| * and running the service instances through the service lifecycle: | |||||
| * <ul> | |||||
| * <li>log enable | |||||
| * <li>contextualise | |||||
| * <li>service | |||||
| * <li>parameterise | |||||
| * <li>initialise | |||||
| * <li>use | |||||
| * <li>dispose | |||||
| * </ul> | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class InstantiatingServiceManager | |||||
| extends AbstractLogEnabled | |||||
| implements ServiceManager, Contextualizable, Parameterizable, Serviceable, Disposable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( InstantiatingServiceManager.class ); | |||||
| /** Map from service class -> service object. */ | |||||
| private Map m_services = new HashMap(); | |||||
| /** The objects (services and factories) that have been created by this mgr. */ | |||||
| private List m_objects = new ArrayList(); | |||||
| /** Other services used by this service manager. */ | |||||
| private TypeFactory m_typeFactory; | |||||
| private RoleManager m_roleManager; | |||||
| private ServiceManager m_serviceManager; | |||||
| private Parameters m_parameters; | |||||
| private TypeManager m_typeManager; | |||||
| private Context m_context; | |||||
| public void contextualize( final Context context ) throws ContextException | |||||
| { | |||||
| m_context = context; | |||||
| } | |||||
| public void parameterize( final Parameters parameters ) throws ParameterException | |||||
| { | |||||
| m_parameters = parameters; | |||||
| } | |||||
| /** | |||||
| * Pass the <code>ServiceManager</code> to the <code>servicable</code>. | |||||
| * The <code>Servicable</code> implementation should use the specified | |||||
| * <code>ServiceManager</code> to acquire the components it needs for | |||||
| * execution. | |||||
| * | |||||
| * @param manager The <code>ServiceManager</code> which this | |||||
| * <code>Servicable</code> uses. | |||||
| */ | |||||
| public void service( final ServiceManager manager ) | |||||
| throws ServiceException | |||||
| { | |||||
| m_serviceManager = manager; | |||||
| m_roleManager = (RoleManager)manager.lookup( RoleManager.ROLE ); | |||||
| m_typeManager = (TypeManager)manager.lookup( TypeManager.ROLE ); | |||||
| } | |||||
| /** | |||||
| * Disposes this service manager, and all services created by it. | |||||
| */ | |||||
| public void dispose() | |||||
| { | |||||
| // Dispose the services | |||||
| for( Iterator iterator = m_objects.iterator(); iterator.hasNext(); ) | |||||
| { | |||||
| final Object object = iterator.next(); | |||||
| if( object instanceof Disposable ) | |||||
| { | |||||
| ( (Disposable)object ).dispose(); | |||||
| } | |||||
| } | |||||
| // Ditch state | |||||
| m_services = null; | |||||
| m_typeFactory = null; | |||||
| m_objects = null; | |||||
| m_parameters = null; | |||||
| m_roleManager = null; | |||||
| m_serviceManager = null; | |||||
| } | |||||
| /** | |||||
| * Determines if this service manager contains a particular service. | |||||
| */ | |||||
| public boolean hasService( final String serviceRole ) | |||||
| { | |||||
| // If we have already instantiated the service, or if we know how | |||||
| // to instantiate it, then return true | |||||
| if( m_services.containsKey( serviceRole ) ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| try | |||||
| { | |||||
| return getFactory().canCreate( serviceRole ); | |||||
| } | |||||
| catch( TypeException e ) | |||||
| { | |||||
| // Throw away exception - yuck | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| * Locates the type factory to use to instantiate service factories. | |||||
| */ | |||||
| private TypeFactory getFactory() throws TypeException | |||||
| { | |||||
| if( m_typeFactory == null ) | |||||
| { | |||||
| m_typeFactory = m_typeManager.getFactory( ServiceFactory.ROLE ); | |||||
| } | |||||
| return m_typeFactory; | |||||
| } | |||||
| /** | |||||
| * Locates a service instance. | |||||
| */ | |||||
| public Object lookup( final String serviceRole ) | |||||
| throws ServiceException | |||||
| { | |||||
| Object service = m_services.get( serviceRole ); | |||||
| if( service == null ) | |||||
| { | |||||
| // Create the service | |||||
| service = createService( serviceRole ); | |||||
| m_services.put( serviceRole, service ); | |||||
| } | |||||
| return service; | |||||
| } | |||||
| /** | |||||
| * Releases a service. | |||||
| */ | |||||
| public void release( final Object service ) | |||||
| { | |||||
| } | |||||
| /** | |||||
| * Creates the service object for a service role. | |||||
| */ | |||||
| private Object createService( final String serviceRole ) throws ServiceException | |||||
| { | |||||
| try | |||||
| { | |||||
| // Create the factory | |||||
| final ServiceFactory factory = (ServiceFactory)getFactory().create( serviceRole ); | |||||
| setupObject( factory ); | |||||
| // Create the service | |||||
| final Object service = factory.createService(); | |||||
| // Check the service is assignable to the role type | |||||
| final RoleInfo roleInfo = m_roleManager.getRole( serviceRole ); | |||||
| final Class serviceType = roleInfo.getType(); | |||||
| if( serviceType != null && !serviceType.isInstance( service ) ) | |||||
| { | |||||
| final String message = REZ.getString( "mismatched-service-type.error", | |||||
| serviceRole, service.getClass().getName() ); | |||||
| throw new ServiceException( message ); | |||||
| } | |||||
| setupObject( service ); | |||||
| return service; | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "create-service.error", serviceRole ); | |||||
| throw new ServiceException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Sets-up an object, taking it through the lifecycle steps. | |||||
| */ | |||||
| private void setupObject( final Object object ) | |||||
| throws Exception | |||||
| { | |||||
| setupLogger( object ); | |||||
| if( m_context != null && object instanceof Contextualizable ) | |||||
| { | |||||
| ( (Contextualizable)object ).contextualize( m_context ); | |||||
| } | |||||
| if( object instanceof Serviceable ) | |||||
| { | |||||
| ( (Serviceable)object ).service( m_serviceManager ); | |||||
| } | |||||
| if( m_parameters != null && object instanceof Parameterizable ) | |||||
| { | |||||
| ( (Parameterizable)object ).parameterize( m_parameters ); | |||||
| } | |||||
| if( object instanceof Initializable ) | |||||
| { | |||||
| ( (Initializable)object ).initialize(); | |||||
| } | |||||
| m_objects.add( object ); | |||||
| } | |||||
| } | |||||
| @@ -1,3 +0,0 @@ | |||||
| unknown-service-type.error=Unknown service "{0}". | |||||
| mismatched-service-type.error=Service factory for service "{0}" produced an object of unexpected type {1}. | |||||
| create-service.error=Could not create service "{0}". | |||||
| @@ -1,268 +0,0 @@ | |||||
| /* | |||||
| * 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.components.store; | |||||
| import java.io.File; | |||||
| import java.util.HashMap; | |||||
| import java.util.Hashtable; | |||||
| import java.util.Map; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.interfaces.model.DefaultNameValidator; | |||||
| import org.apache.myrmidon.interfaces.model.NameValidator; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
| /** | |||||
| * This is the Default implementation of PropertyStore. It follows | |||||
| * the following rules; | |||||
| * | |||||
| * <ul> | |||||
| * <li>The property names must pass DefaultNameValidator checks</li> | |||||
| * <li>The store is mutable</li> | |||||
| * <li>If the key is TaskContext.NAME then value must be a string.</li> | |||||
| * <li>If the key is TaskContext.BASE_DIRECTORY then value must be a key.</li> | |||||
| * </ul> | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * @see org.apache.myrmidon.interfaces.property.PropertyStore | |||||
| */ | |||||
| public class DefaultPropertyStore | |||||
| implements PropertyStore | |||||
| { | |||||
| private final static Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultPropertyStore.class ); | |||||
| /** | |||||
| * The parent store (may be null). | |||||
| */ | |||||
| private final PropertyStore m_parent; | |||||
| /** | |||||
| * The name validator to check property names against. | |||||
| */ | |||||
| private final NameValidator m_validator; | |||||
| /** | |||||
| * The underlying map where propertys are actually stored. | |||||
| */ | |||||
| private final Map m_contextData = new Hashtable(); | |||||
| /** | |||||
| * Construct a PropertyStore with no parent and | |||||
| * default name-validator. | |||||
| */ | |||||
| public DefaultPropertyStore() | |||||
| { | |||||
| this( "", null, null ); | |||||
| } | |||||
| /** | |||||
| * Construct a PropertyStore with specified parent. | |||||
| * | |||||
| * @param parent the parent PropertyStore (may be null). | |||||
| * @param validator the validator to use to check property names (may be null). | |||||
| */ | |||||
| public DefaultPropertyStore( final String name, | |||||
| final PropertyStore parent, | |||||
| final NameValidator validator ) | |||||
| { | |||||
| m_parent = parent; | |||||
| NameValidator candidateValidator = validator; | |||||
| if( null == candidateValidator ) | |||||
| { | |||||
| candidateValidator = createDefaultNameValidator(); | |||||
| } | |||||
| m_validator = candidateValidator; | |||||
| m_contextData.put( TaskContext.NAME, name ); | |||||
| } | |||||
| /** | |||||
| * Set the property with specified name to specified value. | |||||
| * The specific implementation will apply various rules | |||||
| * before setting the property. | |||||
| * | |||||
| * @param name the name of property | |||||
| * @param value the value of property | |||||
| * @throws TaskException if property can not be set | |||||
| */ | |||||
| public void setProperty( final String name, final Object value ) | |||||
| throws TaskException | |||||
| { | |||||
| checkPropertyName( name ); | |||||
| checkPropertyValid( name, value ); | |||||
| if ( value == null ) | |||||
| { | |||||
| m_contextData.remove( name ); | |||||
| } | |||||
| else | |||||
| { | |||||
| m_contextData.put( name, value ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Return <code>true</code> if the specified property is set. | |||||
| * | |||||
| * @param name the name of property | |||||
| */ | |||||
| public boolean isPropertySet( final String name ) | |||||
| { | |||||
| try | |||||
| { | |||||
| getProperty( name ); | |||||
| return true; | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| * Retrieve the value of specified property. | |||||
| * Will return null if no such property exists. | |||||
| * | |||||
| * @param name the name of the property | |||||
| * @return the value of the property, or null if no such property | |||||
| * @throws TaskException if theres an error retrieving property, such | |||||
| * as an invalid property name | |||||
| */ | |||||
| public Object getProperty( final String name ) | |||||
| throws TaskException | |||||
| { | |||||
| Object value = m_contextData.get( name ); | |||||
| if( value != null ) | |||||
| { | |||||
| return value; | |||||
| } | |||||
| if( m_parent != null ) | |||||
| { | |||||
| return m_parent.getProperty( name ); | |||||
| } | |||||
| final String message = REZ.getString( "unknown-prop.error", name ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| /** | |||||
| * Retrieve a copy of all the properties that are "in-scope" | |||||
| * for store. | |||||
| * | |||||
| * @return a copy of all the properties that are "in-scope" | |||||
| * for store. | |||||
| * @throws TaskException if theres an error retrieving propertys | |||||
| */ | |||||
| public Map getProperties() | |||||
| throws TaskException | |||||
| { | |||||
| final Map properties = new HashMap(); | |||||
| if( m_parent != null ) | |||||
| { | |||||
| properties.putAll( m_parent.getProperties() ); | |||||
| } | |||||
| properties.putAll( m_contextData ); | |||||
| return properties; | |||||
| } | |||||
| /** | |||||
| * Return a child PropertyStore with specified name. | |||||
| * This is to allow support for scoped stores. However a | |||||
| * store may choose to be unscoped and just return a | |||||
| * reference to itself. | |||||
| * | |||||
| * @param name the name of child store | |||||
| * @return the child store | |||||
| * @throws TaskException if theres an error creating child store | |||||
| */ | |||||
| public PropertyStore createChildStore( final String name ) | |||||
| throws TaskException | |||||
| { | |||||
| // Build the name for the new store | |||||
| final String thisName = (String)m_contextData.get( TaskContext.NAME ); | |||||
| final String newName; | |||||
| if( name == null || name.length() == 0 ) | |||||
| { | |||||
| newName = thisName; | |||||
| } | |||||
| else if( thisName.length() == 0 ) | |||||
| { | |||||
| newName = name; | |||||
| } | |||||
| else | |||||
| { | |||||
| newName = thisName + "." + name; | |||||
| } | |||||
| return new DefaultPropertyStore( newName, this, m_validator ); | |||||
| } | |||||
| /** | |||||
| * Checks that the supplied property name is valid. | |||||
| */ | |||||
| private void checkPropertyName( final String name ) | |||||
| throws TaskException | |||||
| { | |||||
| try | |||||
| { | |||||
| m_validator.validate( name ); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| String message = REZ.getString( "bad-property-name.error", name ); | |||||
| throw new TaskException( message, e ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Make sure property is valid if it is one of the "magic" properties. | |||||
| * | |||||
| * @param name the name of property | |||||
| * @param value the value of proeprty | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| private void checkPropertyValid( final String name, final Object value ) | |||||
| throws TaskException | |||||
| { | |||||
| if( TaskContext.BASE_DIRECTORY.equals( name ) && !( value instanceof File ) ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "bad-property.error", | |||||
| TaskContext.BASE_DIRECTORY, | |||||
| File.class.getName() ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| else if( TaskContext.NAME.equals( name ) && !( value instanceof String ) ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "bad-property.error", | |||||
| TaskContext.NAME, | |||||
| String.class.getName() ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Create an instance of the default the name validator. | |||||
| * | |||||
| * @return the default NameValidator | |||||
| */ | |||||
| private static NameValidator createDefaultNameValidator() | |||||
| { | |||||
| final DefaultNameValidator defaultValidator = new DefaultNameValidator(); | |||||
| defaultValidator.setAllowInternalWhitespace( false ); | |||||
| defaultValidator.setAdditionalInternalCharacters( "_-.+" ); | |||||
| return defaultValidator; | |||||
| } | |||||
| } | |||||
| @@ -1,5 +0,0 @@ | |||||
| unknown-prop.error=Unknown property "{0}". | |||||
| bad-property.error=Property "{0}" must have a value of type {1}. | |||||
| bad-property-name.error=Invalid property name "{0}". | |||||
| null-resolved-value.error=Value "{0}" resolved to null. | |||||
| bad-resolve.error=Unable to resolve value "{0}". | |||||
| @@ -1,139 +0,0 @@ | |||||
| /* | |||||
| * 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.components.type; | |||||
| import java.util.HashMap; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.avalon.framework.service.Serviceable; | |||||
| import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
| import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| import org.apache.myrmidon.interfaces.type.TypeException; | |||||
| import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| /** | |||||
| * The interface that is used to manage types. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultTypeManager | |||||
| implements TypeManager, Serviceable | |||||
| { | |||||
| private static final Resources REZ | |||||
| = ResourceManager.getPackageResources( DefaultTypeManager.class ); | |||||
| ///Parent type manager to inherit values from. | |||||
| private final DefaultTypeManager m_parent; | |||||
| ///Maps role Class to MultiSourceTypeFactory. | |||||
| private final HashMap m_roleMap = new HashMap(); | |||||
| private RoleManager m_roleManager; | |||||
| public DefaultTypeManager() | |||||
| { | |||||
| this( null ); | |||||
| } | |||||
| private DefaultTypeManager( final DefaultTypeManager parent ) | |||||
| { | |||||
| m_parent = parent; | |||||
| if( m_parent != null ) | |||||
| { | |||||
| m_roleManager = m_parent.m_roleManager; | |||||
| } | |||||
| } | |||||
| public void service( final ServiceManager serviceManager ) | |||||
| throws ServiceException | |||||
| { | |||||
| m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||||
| } | |||||
| public void registerType( final String roleName, | |||||
| final String shorthandName, | |||||
| final TypeFactory factory ) | |||||
| throws TypeException | |||||
| { | |||||
| final MultiSourceTypeFactory msFactory = createFactory( roleName ); | |||||
| msFactory.register( shorthandName, factory ); | |||||
| } | |||||
| public TypeFactory getFactory( final String roleName ) | |||||
| throws TypeException | |||||
| { | |||||
| return createFactory( roleName ); | |||||
| } | |||||
| public TypeManager createChildTypeManager() | |||||
| { | |||||
| return new DefaultTypeManager( this ); | |||||
| } | |||||
| private final MultiSourceTypeFactory lookupFactory( final String roleName ) | |||||
| { | |||||
| return (MultiSourceTypeFactory)m_roleMap.get( roleName ); | |||||
| } | |||||
| /** | |||||
| * Get a factory of appropriate role. | |||||
| * Create a Factory if none exists with same name. | |||||
| * | |||||
| * @param roleName the role name | |||||
| * @return the Factory for interface | |||||
| * @exception TypeException role does not specify accessible work interface | |||||
| */ | |||||
| private MultiSourceTypeFactory createFactory( final String roleName ) | |||||
| throws TypeException | |||||
| { | |||||
| MultiSourceTypeFactory factory = (MultiSourceTypeFactory)m_roleMap.get( roleName ); | |||||
| if( null != factory ) | |||||
| { | |||||
| return factory; | |||||
| } | |||||
| final MultiSourceTypeFactory parentFactory = getParentTypedFactory( roleName ); | |||||
| if( null != parentFactory ) | |||||
| { | |||||
| factory = new MultiSourceTypeFactory( parentFactory ); | |||||
| } | |||||
| ///If we haven't got factory try to create a new one | |||||
| if( null == factory ) | |||||
| { | |||||
| // Lookup the role type | |||||
| final RoleInfo role = m_roleManager.getRole( roleName ); | |||||
| if( role == null ) | |||||
| { | |||||
| final String message = REZ.getString( "unknown-role.error", roleName ); | |||||
| throw new TypeException( message ); | |||||
| } | |||||
| factory = new MultiSourceTypeFactory( role.getType() ); | |||||
| } | |||||
| m_roleMap.put( roleName, factory ); | |||||
| return factory; | |||||
| } | |||||
| private MultiSourceTypeFactory getParentTypedFactory( final String roleName ) | |||||
| { | |||||
| if( null != m_parent ) | |||||
| { | |||||
| return m_parent.lookupFactory( roleName ); | |||||
| } | |||||
| else | |||||
| { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,124 +0,0 @@ | |||||
| /* | |||||
| * 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.components.type; | |||||
| import java.util.HashMap; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.myrmidon.interfaces.type.TypeException; | |||||
| import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
| /** | |||||
| * This factory acts as a proxy to set of object factories. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class MultiSourceTypeFactory | |||||
| implements TypeFactory | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( MultiSourceTypeFactory.class ); | |||||
| ///Parent Selector | |||||
| private final MultiSourceTypeFactory m_parent; | |||||
| ///Map of name->factory list | |||||
| private final HashMap m_factories = new HashMap(); | |||||
| ///Type expected to be created from factories | |||||
| private final Class m_type; | |||||
| public MultiSourceTypeFactory( final Class type ) | |||||
| { | |||||
| m_type = type; | |||||
| m_parent = null; | |||||
| } | |||||
| public MultiSourceTypeFactory( final MultiSourceTypeFactory parent ) | |||||
| { | |||||
| m_type = parent.getType(); | |||||
| m_parent = parent; | |||||
| } | |||||
| /** | |||||
| * Populate the ComponentSelector. | |||||
| */ | |||||
| public void register( final String name, final TypeFactory factory ) | |||||
| { | |||||
| m_factories.put( name, factory ); | |||||
| } | |||||
| /** | |||||
| * Determines if this factory can create instances of a particular type. | |||||
| */ | |||||
| public boolean canCreate( final String name ) | |||||
| { | |||||
| return ( findFactory( name ) != null ); | |||||
| } | |||||
| /** | |||||
| * Create a type instance based on name. | |||||
| * | |||||
| * @param name the name | |||||
| * @return the type instance | |||||
| * @exception TypeException if an error occurs | |||||
| */ | |||||
| public Object create( final String name ) | |||||
| throws TypeException | |||||
| { | |||||
| // Locate the factory to use | |||||
| TypeFactory factory = findFactory( name ); | |||||
| if( null == factory ) | |||||
| { | |||||
| final String message = REZ.getString( "no-factory.error", name ); | |||||
| throw new TypeException( message ); | |||||
| } | |||||
| // Create the object | |||||
| final Object object = factory.create( name ); | |||||
| if( m_type != null && !m_type.isInstance( object ) ) | |||||
| { | |||||
| final String message = REZ.getString( "mismatched-type.error", | |||||
| name, object.getClass().getName() ); | |||||
| throw new TypeException( message ); | |||||
| } | |||||
| return object; | |||||
| } | |||||
| /** | |||||
| * Locates the type factory to use for a particular type. | |||||
| */ | |||||
| private TypeFactory findFactory( final String name ) | |||||
| { | |||||
| TypeFactory factory = getTypeFactory( name ); | |||||
| if( null == factory && null != m_parent ) | |||||
| { | |||||
| factory = m_parent.getTypeFactory( name ); | |||||
| } | |||||
| return factory; | |||||
| } | |||||
| /** | |||||
| * Retrieve type managed by selector. | |||||
| * Used by other instances of TypedComponentSelector. | |||||
| * | |||||
| * @return the type class | |||||
| */ | |||||
| private final Class getType() | |||||
| { | |||||
| return m_type; | |||||
| } | |||||
| private final TypeFactory getTypeFactory( final String name ) | |||||
| { | |||||
| return (TypeFactory)m_factories.get( name ); | |||||
| } | |||||
| } | |||||
| @@ -1,9 +0,0 @@ | |||||
| # DefaultTypeManager | |||||
| unknown-role.error=Cannot create a type factory for unknown role {0}. | |||||
| # MultiSourceTypeFactory | |||||
| no-instantiate.error=Unable to instantiate ({0}). | |||||
| no-mapping.error=Malconfigured factory, no classname for ({0}). | |||||
| no-factory.error=Failed to locate factory for {0}. | |||||
| mismatched-type.error=Factory for type {0} created an object of incompatible type {1}. | |||||
| no-work-interface.error=Role {0} does not specify accessible work interface. | |||||
| @@ -1,61 +0,0 @@ | |||||
| /* | |||||
| * 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.components.workspace; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
| /** | |||||
| * Frames in which tasks are executed. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultExecutionFrame | |||||
| implements ExecutionFrame | |||||
| { | |||||
| private final Logger m_logger; | |||||
| private final PropertyStore m_propertyStore; | |||||
| private final ServiceManager m_serviceManager; | |||||
| public DefaultExecutionFrame( final Logger logger, | |||||
| final PropertyStore propertyStore, | |||||
| final ServiceManager serviceManager ) | |||||
| { | |||||
| m_logger = logger; | |||||
| m_propertyStore = propertyStore; | |||||
| m_serviceManager = serviceManager; | |||||
| } | |||||
| /** | |||||
| * Returns the logger which is to be supplied to tasks. | |||||
| */ | |||||
| public Logger getLogger() | |||||
| { | |||||
| return m_logger; | |||||
| } | |||||
| /** | |||||
| * Returns the set of services to use to create, configure, and execute | |||||
| * tasks. | |||||
| */ | |||||
| public ServiceManager getServiceManager() | |||||
| { | |||||
| return m_serviceManager; | |||||
| } | |||||
| /** | |||||
| * Returns the set of properties to be supplied to tasks. | |||||
| */ | |||||
| public PropertyStore getProperties() | |||||
| { | |||||
| return m_propertyStore; | |||||
| } | |||||
| } | |||||
| @@ -1,382 +0,0 @@ | |||||
| /* | |||||
| * 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.components.workspace; | |||||
| import java.io.File; | |||||
| import java.util.Map; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.excalibur.io.FileUtil; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| import org.apache.avalon.framework.service.DefaultServiceManager; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
| /** | |||||
| * Default implementation of TaskContext. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultTaskContext | |||||
| implements TaskContext | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultTaskContext.class ); | |||||
| private final ServiceManager m_serviceManager; | |||||
| private final Logger m_logger; | |||||
| private final PropertyStore m_store; | |||||
| private PropertyResolver m_propertyResolver; | |||||
| /** | |||||
| * Constructor that takes both parent context and a service directory. | |||||
| */ | |||||
| public DefaultTaskContext( final ServiceManager serviceManager, | |||||
| final Logger logger, | |||||
| final PropertyStore store ) | |||||
| { | |||||
| m_serviceManager = serviceManager; | |||||
| m_logger = logger; | |||||
| m_store = store; | |||||
| if( null == m_serviceManager ) | |||||
| { | |||||
| throw new NullPointerException( "serviceManager" ); | |||||
| } | |||||
| if( null == m_logger ) | |||||
| { | |||||
| throw new NullPointerException( "logger" ); | |||||
| } | |||||
| if( null == m_store ) | |||||
| { | |||||
| throw new NullPointerException( "store" ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Retrieve Name of task. | |||||
| * | |||||
| * @return the name | |||||
| */ | |||||
| public String getName() | |||||
| { | |||||
| return (String)getProperty( NAME ); | |||||
| } | |||||
| /** | |||||
| * Retrieve base directory. | |||||
| * | |||||
| * @return the base directory | |||||
| */ | |||||
| public File getBaseDirectory() | |||||
| { | |||||
| return (File)getProperty( BASE_DIRECTORY ); | |||||
| } | |||||
| /** | |||||
| * Retrieve a service that is offered by the runtime. | |||||
| * The actual services registered and in place for the | |||||
| * task is determined by the container. The returned service | |||||
| * <b>MUST</b> implement the specified interface. | |||||
| * | |||||
| * @param serviceClass the interface class that defines the service | |||||
| * @return an instance of the service implementing interface specified by parameter | |||||
| * @exception TaskException is thrown when the service is unavailable or not supported | |||||
| */ | |||||
| public Object getService( final Class serviceClass ) | |||||
| throws TaskException | |||||
| { | |||||
| final String name = serviceClass.getName(); | |||||
| //Note that this will chain up to parent ServiceManagers (if any) | |||||
| if( null != m_serviceManager && m_serviceManager.hasService( name ) ) | |||||
| { | |||||
| try | |||||
| { | |||||
| return m_serviceManager.lookup( name ); | |||||
| } | |||||
| catch( final ServiceException se ) | |||||
| { | |||||
| throw new TaskException( se.getMessage(), se ); | |||||
| } | |||||
| } | |||||
| // Not found | |||||
| final String message = REZ.getString( "bad-find-service.error", name ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| /** | |||||
| * Resolve filename. | |||||
| * This involves resolving it against baseDirectory and | |||||
| * removing ../ and ./ references. It also means formatting | |||||
| * it appropriately for the particular OS (ie different OS have | |||||
| * different volumes, file conventions etc) | |||||
| * | |||||
| * @param filename the filename to resolve | |||||
| * @return the resolved filename | |||||
| */ | |||||
| public File resolveFile( final String filename ) | |||||
| { | |||||
| return FileUtil.resolveFile( getBaseDirectory(), filename ); | |||||
| } | |||||
| /** | |||||
| * Resolve a value according to the context. | |||||
| * This involves evaluating the string and thus removing | |||||
| * ${} sequences according to the rules specified at | |||||
| * ............ | |||||
| * | |||||
| * @param value the value to resolve | |||||
| * @return the resolved value | |||||
| */ | |||||
| public Object resolveValue( final String value ) | |||||
| throws TaskException | |||||
| { | |||||
| try | |||||
| { | |||||
| if( null == m_propertyResolver ) | |||||
| { | |||||
| m_propertyResolver = (PropertyResolver)getService( PropertyResolver.class ); | |||||
| } | |||||
| final Object object = | |||||
| m_propertyResolver.resolveProperties( value, this ); | |||||
| if( null == object ) | |||||
| { | |||||
| final String message = REZ.getString( "null-resolved-value.error", value ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| return object; | |||||
| } | |||||
| catch( final TaskException te ) | |||||
| { | |||||
| final String message = REZ.getString( "bad-resolve.error", value ); | |||||
| throw new TaskException( message, te ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Retrieve property for name. | |||||
| * | |||||
| * @param name the name of property | |||||
| * @return the value of the property | |||||
| */ | |||||
| public Object getProperty( final String name ) | |||||
| { | |||||
| try | |||||
| { | |||||
| return m_store.getProperty( name ); | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Retrieve a copy of all the properties accessible via context. | |||||
| * | |||||
| * @return the map of all property names to values | |||||
| */ | |||||
| public Map getProperties() | |||||
| throws TaskException | |||||
| { | |||||
| return m_store.getProperties(); | |||||
| } | |||||
| /** | |||||
| * Set property value in current context. | |||||
| * | |||||
| * @param name the name of property | |||||
| * @param value the value of property | |||||
| */ | |||||
| public void setProperty( final String name, final Object value ) | |||||
| throws TaskException | |||||
| { | |||||
| m_store.setProperty( name, value ); | |||||
| } | |||||
| /** | |||||
| * Log a debug message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void debug( final String message ) | |||||
| { | |||||
| m_logger.debug( message ); | |||||
| } | |||||
| /** | |||||
| * Log a debug message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void debug( final String message, final Throwable throwable ) | |||||
| { | |||||
| m_logger.debug( message, throwable ); | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "debug" will be logged. | |||||
| * | |||||
| * @return true if "debug" messages will be logged | |||||
| */ | |||||
| public boolean isDebugEnabled() | |||||
| { | |||||
| return m_logger.isDebugEnabled(); | |||||
| } | |||||
| /** | |||||
| * Log a verbose message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void verbose( String message ) | |||||
| { | |||||
| m_logger.info( message ); | |||||
| } | |||||
| /** | |||||
| * Log a verbose message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void verbose( String message, Throwable throwable ) | |||||
| { | |||||
| m_logger.info( message, throwable ); | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "verbose" will be logged. | |||||
| * | |||||
| * @return true if "verbose" messages will be logged | |||||
| */ | |||||
| public boolean isVerboseEnabled() | |||||
| { | |||||
| return m_logger.isInfoEnabled(); | |||||
| } | |||||
| /** | |||||
| * Log a info message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void info( final String message ) | |||||
| { | |||||
| m_logger.warn( message ); | |||||
| } | |||||
| /** | |||||
| * Log a info message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void info( final String message, final Throwable throwable ) | |||||
| { | |||||
| m_logger.warn( message, throwable ); | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "info" will be logged. | |||||
| * | |||||
| * @return true if "info" messages will be logged | |||||
| */ | |||||
| public boolean isInfoEnabled() | |||||
| { | |||||
| return m_logger.isWarnEnabled(); | |||||
| } | |||||
| /** | |||||
| * Log a warn message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void warn( final String message ) | |||||
| { | |||||
| m_logger.error( message ); | |||||
| } | |||||
| /** | |||||
| * Log a warn message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void warn( final String message, final Throwable throwable ) | |||||
| { | |||||
| m_logger.error( message, throwable ); | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "warn" will be logged. | |||||
| * | |||||
| * @return true if "warn" messages will be logged | |||||
| */ | |||||
| public boolean isWarnEnabled() | |||||
| { | |||||
| return m_logger.isErrorEnabled(); | |||||
| } | |||||
| /** | |||||
| * Log a error message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void error( final String message ) | |||||
| { | |||||
| m_logger.fatalError( message ); | |||||
| } | |||||
| /** | |||||
| * Log a error message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void error( final String message, final Throwable throwable ) | |||||
| { | |||||
| m_logger.fatalError( message, throwable ); | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "error" will be logged. | |||||
| * | |||||
| * @return true if "error" messages will be logged | |||||
| */ | |||||
| public boolean isErrorEnabled() | |||||
| { | |||||
| return m_logger.isFatalErrorEnabled(); | |||||
| } | |||||
| /** | |||||
| * Create a Child Context. | |||||
| * This allows separate hierarchly contexts to be easily constructed. | |||||
| * | |||||
| * @param name the name of sub-context | |||||
| * @return the created TaskContext | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| public TaskContext createSubContext( final String name ) | |||||
| throws TaskException | |||||
| { | |||||
| final PropertyStore store = m_store.createChildStore( name ); | |||||
| final DefaultServiceManager serviceManager = | |||||
| new DefaultServiceManager( m_serviceManager ); | |||||
| final Logger logger = m_logger.getChildLogger( name ); | |||||
| return new DefaultTaskContext( serviceManager, logger, store ); | |||||
| } | |||||
| } | |||||
| @@ -1,437 +0,0 @@ | |||||
| /* | |||||
| * 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.components.workspace; | |||||
| import java.io.File; | |||||
| import java.util.HashMap; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.avalon.framework.context.ContextException; | |||||
| import org.apache.avalon.framework.context.Contextualizable; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| import org.apache.avalon.framework.service.DefaultServiceManager; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| 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; | |||||
| import org.apache.myrmidon.interfaces.executor.ExecutionContainer; | |||||
| import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
| import org.apache.myrmidon.interfaces.executor.Executor; | |||||
| import org.apache.myrmidon.interfaces.model.Dependency; | |||||
| import org.apache.myrmidon.interfaces.model.Project; | |||||
| import org.apache.myrmidon.interfaces.model.Target; | |||||
| import org.apache.myrmidon.interfaces.model.TypeLib; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| import org.apache.myrmidon.interfaces.workspace.Workspace; | |||||
| import org.apache.myrmidon.listeners.ProjectListener; | |||||
| /** | |||||
| * This is the default implementation of Workspace. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultWorkspace | |||||
| extends AbstractLogEnabled | |||||
| implements Workspace, ExecutionContainer, Contextualizable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultWorkspace.class ); | |||||
| private Executor m_executor; | |||||
| private ProjectListenerSupport m_listenerSupport = new ProjectListenerSupport(); | |||||
| private ServiceManager m_serviceManager; | |||||
| private PropertyStore m_baseStore; | |||||
| private TypeManager m_typeManager; | |||||
| private Deployer m_deployer; | |||||
| private Context m_context; | |||||
| /** A map from Project object -> ProjectEntry for that project. */ | |||||
| private HashMap m_entries = new HashMap(); | |||||
| /** | |||||
| * Add a listener to project events. | |||||
| * | |||||
| * @param listener the listener | |||||
| */ | |||||
| public void addProjectListener( final ProjectListener listener ) | |||||
| { | |||||
| m_listenerSupport.addProjectListener( listener ); | |||||
| } | |||||
| /** | |||||
| * Remove a listener from project events. | |||||
| * | |||||
| * @param listener the listener | |||||
| */ | |||||
| public void removeProjectListener( final ProjectListener listener ) | |||||
| { | |||||
| m_listenerSupport.removeProjectListener( listener ); | |||||
| } | |||||
| /** | |||||
| * Sets the root execution frame. | |||||
| */ | |||||
| public void setRootExecutionFrame( final ExecutionFrame frame ) throws Exception | |||||
| { | |||||
| m_baseStore = frame.getProperties(); | |||||
| m_serviceManager = frame.getServiceManager(); | |||||
| m_typeManager = (TypeManager)m_serviceManager.lookup( TypeManager.ROLE ); | |||||
| m_executor = (Executor)m_serviceManager.lookup( Executor.ROLE ); | |||||
| m_deployer = (Deployer)m_serviceManager.lookup( Deployer.ROLE ); | |||||
| } | |||||
| public void contextualize( final Context context ) throws ContextException | |||||
| { | |||||
| m_context = context; | |||||
| } | |||||
| /** | |||||
| * Execute a target in a particular project. | |||||
| * Execute in the project context. | |||||
| * | |||||
| * @param project the Project | |||||
| * @param target the name of the target | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| public void executeProject( final Project project, final String target ) | |||||
| throws TaskException | |||||
| { | |||||
| final ProjectEntry entry = getProjectEntry( project ); | |||||
| m_listenerSupport.projectStarted( project.getProjectName() ); | |||||
| executeTarget( entry, target ); | |||||
| m_listenerSupport.projectFinished( project.getProjectName() ); | |||||
| } | |||||
| private File findTypeLib( final String libraryName ) | |||||
| throws Exception | |||||
| { | |||||
| //TODO: In future this will be expanded to allow | |||||
| //users to specify search path or automagically | |||||
| //add entries to lib path (like user specific or | |||||
| //workspace specific) | |||||
| final String name = libraryName.replace( '/', File.separatorChar ) + ".atl"; | |||||
| final File[] extPath = (File[])m_context.get( "myrmidon.antlib.path" ); | |||||
| for( int i = 0; i < extPath.length; i++ ) | |||||
| { | |||||
| final File extDir = extPath[ i ]; | |||||
| final File library = new File( extDir, name ); | |||||
| if( library.exists() ) | |||||
| { | |||||
| if( !library.canRead() ) | |||||
| { | |||||
| final String message = REZ.getString( "no-read.error", library ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| else | |||||
| { | |||||
| return library; | |||||
| } | |||||
| } | |||||
| } | |||||
| final String message = REZ.getString( "no-library.error", libraryName ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| private void deployTypeLib( final Deployer deployer, final Project project ) | |||||
| throws Exception | |||||
| { | |||||
| final TypeLib[] typeLibs = project.getTypeLibs(); | |||||
| for( int i = 0; i < typeLibs.length; i++ ) | |||||
| { | |||||
| final TypeLib typeLib = typeLibs[ i ]; | |||||
| final File file = findTypeLib( typeLib.getLibrary() ); | |||||
| try | |||||
| { | |||||
| final TypeDeployer typeDeployer = deployer.createDeployer( file ); | |||||
| if( null == typeLib.getRole() ) | |||||
| { | |||||
| // Deploy everything in the typelib | |||||
| typeDeployer.deployAll(); | |||||
| } | |||||
| else | |||||
| { | |||||
| // Deploy the specified type | |||||
| typeDeployer.deployType( typeLib.getRole(), typeLib.getName() ); | |||||
| } | |||||
| } | |||||
| catch( final DeploymentException de ) | |||||
| { | |||||
| final String message = REZ.getString( "no-deploy.error", | |||||
| typeLib.getLibrary(), file ); | |||||
| throw new TaskException( message, de ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates an execution frame for a project. | |||||
| */ | |||||
| private ExecutionFrame createExecutionFrame( final Project project ) | |||||
| throws Exception | |||||
| { | |||||
| //Create per frame ComponentManager | |||||
| final DefaultServiceManager serviceManager = | |||||
| new DefaultServiceManager( m_serviceManager ); | |||||
| //Add in child type manager so each frame can register different | |||||
| //sets of tasks etc | |||||
| final TypeManager typeManager = m_typeManager.createChildTypeManager(); | |||||
| serviceManager.put( TypeManager.ROLE, typeManager ); | |||||
| // TODO - Add child role manager and configurer | |||||
| //We need to create a new deployer so that it deploys | |||||
| //to project specific TypeManager | |||||
| final Deployer deployer = m_deployer.createChildDeployer( serviceManager ); | |||||
| serviceManager.put( Deployer.ROLE, deployer ); | |||||
| // Deploy the imported typelibs | |||||
| deployTypeLib( deployer, project ); | |||||
| //We need to place projects and ProjectManager | |||||
| //in ComponentManager so as to support project-local call() | |||||
| // TODO - add project to properties, not services | |||||
| serviceManager.put( Workspace.ROLE, this ); | |||||
| serviceManager.put( Project.ROLE, project ); | |||||
| // Create a logger | |||||
| final Logger logger = | |||||
| new RoutingLogger( getLogger(), m_listenerSupport ); | |||||
| // Properties | |||||
| final PropertyStore store = m_baseStore.createChildStore(""); | |||||
| store.setProperty( TaskContext.BASE_DIRECTORY, project.getBaseDirectory() ); | |||||
| final DefaultExecutionFrame frame = | |||||
| new DefaultExecutionFrame( logger, store, serviceManager ); | |||||
| /** | |||||
| * @todo Should no occur but done for the time being to simplify evolution. | |||||
| */ | |||||
| serviceManager.put( ExecutionFrame.ROLE, frame ); | |||||
| return frame; | |||||
| } | |||||
| private ProjectEntry getProjectEntry( final Project project ) | |||||
| throws TaskException | |||||
| { | |||||
| ProjectEntry entry = (ProjectEntry)m_entries.get( project ); | |||||
| if( null == entry ) | |||||
| { | |||||
| try | |||||
| { | |||||
| final ExecutionFrame frame = createExecutionFrame( project ); | |||||
| entry = new ProjectEntry( project, frame ); | |||||
| m_entries.put( project, entry ); | |||||
| } | |||||
| catch( Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "bad-frame.error" ); | |||||
| throw new TaskException( message, e ); | |||||
| } | |||||
| } | |||||
| return entry; | |||||
| } | |||||
| private Project getProject( final String name, final Project project ) | |||||
| throws TaskException | |||||
| { | |||||
| final Project other = project.getProject( name ); | |||||
| if( null == other ) | |||||
| { | |||||
| //TODO: Fix this so location information included in description | |||||
| final String message = REZ.getString( "no-project.error", name ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| return other; | |||||
| } | |||||
| /** | |||||
| * Helper method to execute a target. | |||||
| * | |||||
| * @param entry the project to execute | |||||
| * @param targetName the name of the target to execute | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| private void executeTarget( final ProjectEntry entry, | |||||
| final String targetName ) | |||||
| throws TaskException | |||||
| { | |||||
| // Locate the target | |||||
| final Target target = entry.getProject().getTarget( targetName ); | |||||
| if( null == target ) | |||||
| { | |||||
| final String message = REZ.getString( "no-target.error", targetName ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| executeTarget( entry, targetName, target ); | |||||
| } | |||||
| /** | |||||
| * Executes a target. Does not execute the target if it has already been | |||||
| * executed. Executes the dependencies of the target, before executing | |||||
| * the target itself. | |||||
| * | |||||
| * @param name the name of target | |||||
| * @param target the target | |||||
| * @param entry the project in which to execute | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| private void executeTarget( final ProjectEntry entry, | |||||
| final String name, | |||||
| final Target target ) | |||||
| throws TaskException | |||||
| { | |||||
| final Project project = entry.getProject(); | |||||
| // Check target state, to see if it has already been executed, and | |||||
| // to check for dependency cycles | |||||
| final TargetState state = entry.getTargetState( target ); | |||||
| if( state == TargetState.FINISHED ) | |||||
| { | |||||
| // Target has been executed | |||||
| return; | |||||
| } | |||||
| if( state == TargetState.TRAVERSING ) | |||||
| { | |||||
| // Cycle in target dependencies | |||||
| final String message = REZ.getString( "target-dependency-cycle.error", name ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| // Set state to indicate this target has been started | |||||
| entry.setTargetState( target, TargetState.TRAVERSING ); | |||||
| // Execute the target's dependencies | |||||
| // Implicit target first | |||||
| if( target != project.getImplicitTarget() ) | |||||
| { | |||||
| executeTarget( entry, "<init>", project.getImplicitTarget() ); | |||||
| } | |||||
| // Named dependencies | |||||
| final Dependency[] dependencies = target.getDependencies(); | |||||
| for( int i = 0; i < dependencies.length; i++ ) | |||||
| { | |||||
| final Dependency dependency = dependencies[ i ]; | |||||
| final String otherProjectName = dependency.getProjectName(); | |||||
| if( otherProjectName != null ) | |||||
| { | |||||
| // Dependency in a referenced project | |||||
| final Project otherProject = getProject( otherProjectName, project ); | |||||
| final ProjectEntry otherEntry = getProjectEntry( otherProject ); | |||||
| executeTarget( otherEntry, dependency.getTargetName() ); | |||||
| } | |||||
| else | |||||
| { | |||||
| // Dependency in this project | |||||
| executeTarget( entry, dependency.getTargetName() ); | |||||
| } | |||||
| } | |||||
| // Now execute the target itself | |||||
| executeTargetNoDeps( entry, name, target ); | |||||
| // Mark target as complete | |||||
| entry.setTargetState( target, TargetState.FINISHED ); | |||||
| } | |||||
| /** | |||||
| * Executes a target. Does not check whether the target has been | |||||
| * executed already, and does not check that its dependencies have been | |||||
| * executed. | |||||
| * | |||||
| * @param entry the project to execute the target in. | |||||
| * @param name the name of the target. | |||||
| * @param target the target itself | |||||
| */ | |||||
| private void executeTargetNoDeps( final ProjectEntry entry, | |||||
| final String name, | |||||
| final Target target ) | |||||
| throws TaskException | |||||
| { | |||||
| final Project project = entry.getProject(); | |||||
| // Notify listeners | |||||
| m_listenerSupport.targetStarted( project.getProjectName(), name ); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( "exec-target.notice", | |||||
| project.getProjectName(), name ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| //TODO - put this back in | |||||
| //frame.getContext().setProperty( Project.TARGET, target ); | |||||
| // Execute all tasks assciated with target | |||||
| final Configuration[] tasks = target.getTasks(); | |||||
| for( int i = 0; i < tasks.length; i++ ) | |||||
| { | |||||
| executeTask( tasks[ i ], entry.getFrame() ); | |||||
| } | |||||
| // Notify listeners | |||||
| m_listenerSupport.targetFinished(); | |||||
| } | |||||
| /** | |||||
| * Execute a task. | |||||
| * | |||||
| * @param task the task definition | |||||
| * @param frame the frame to execute in | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| private void executeTask( final Configuration task, final ExecutionFrame frame ) | |||||
| throws TaskException | |||||
| { | |||||
| final String name = task.getName(); | |||||
| if( getLogger().isDebugEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( "exec-task.notice", name ); | |||||
| getLogger().debug( message ); | |||||
| } | |||||
| //is setting name even necessary ??? | |||||
| frame.getProperties().setProperty( TaskContext.NAME, name ); | |||||
| //notify listeners | |||||
| m_listenerSupport.taskStarted( name ); | |||||
| //run task | |||||
| m_executor.execute( task, frame ); | |||||
| //notify listeners task has ended | |||||
| m_listenerSupport.taskFinished(); | |||||
| } | |||||
| } | |||||
| @@ -1,62 +0,0 @@ | |||||
| /* | |||||
| * 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.components.workspace; | |||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
| import org.apache.myrmidon.interfaces.model.Project; | |||||
| import org.apache.myrmidon.interfaces.model.Target; | |||||
| /** | |||||
| * This contains details for each project that is being executed by a | |||||
| * DefaultWorkspace. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| final class ProjectEntry | |||||
| { | |||||
| private final Project m_project; | |||||
| private final ExecutionFrame m_frame; | |||||
| /** Map from Target -> TargetState for that target. */ | |||||
| private final Map m_targetState = new HashMap(); | |||||
| public ProjectEntry( final Project project, | |||||
| final ExecutionFrame frame ) | |||||
| { | |||||
| m_project = project; | |||||
| m_frame = frame; | |||||
| } | |||||
| public Project getProject() | |||||
| { | |||||
| return m_project; | |||||
| } | |||||
| public ExecutionFrame getFrame() | |||||
| { | |||||
| return m_frame; | |||||
| } | |||||
| public TargetState getTargetState( final Target target ) | |||||
| { | |||||
| TargetState state = (TargetState)m_targetState.get( target ); | |||||
| if( state == null ) | |||||
| { | |||||
| state = TargetState.NOT_STARTED; | |||||
| } | |||||
| return state; | |||||
| } | |||||
| public void setTargetState( final Target target, final TargetState state ) | |||||
| { | |||||
| m_targetState.put( target, state ); | |||||
| } | |||||
| } | |||||
| @@ -1,224 +0,0 @@ | |||||
| /* | |||||
| * 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.components.workspace; | |||||
| import org.apache.myrmidon.listeners.LogEvent; | |||||
| import org.apache.myrmidon.listeners.ProjectListener; | |||||
| /** | |||||
| * Support for the project listener event dispatching. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class ProjectListenerSupport | |||||
| implements LogEvent | |||||
| { | |||||
| private ProjectListener[] m_listeners = new ProjectListener[ 0 ]; | |||||
| private String m_projectName; | |||||
| private String m_targetName; | |||||
| private String m_taskName; | |||||
| private String m_message; | |||||
| private Throwable m_throwable; | |||||
| /** | |||||
| * Add an extra project listener that wants to receive notification of listener events. | |||||
| * | |||||
| * @param listener the listener | |||||
| */ | |||||
| public void addProjectListener( final ProjectListener listener ) | |||||
| { | |||||
| final ProjectListener[] listeners = new ProjectListener[ m_listeners.length + 1 ]; | |||||
| System.arraycopy( m_listeners, 0, listeners, 0, m_listeners.length ); | |||||
| listeners[ m_listeners.length ] = listener; | |||||
| m_listeners = listeners; | |||||
| } | |||||
| /** | |||||
| * Remove a project listener that wants to receive notification of listener events. | |||||
| * | |||||
| * @param listener the listener | |||||
| */ | |||||
| public void removeProjectListener( final ProjectListener listener ) | |||||
| { | |||||
| int found = -1; | |||||
| for( int i = 0; i < m_listeners.length; i++ ) | |||||
| { | |||||
| if( listener == m_listeners[ i ] ) | |||||
| { | |||||
| found = i; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if( -1 == found ) | |||||
| { | |||||
| return; | |||||
| } | |||||
| final ProjectListener[] listeners = new ProjectListener[ m_listeners.length - 1 ]; | |||||
| System.arraycopy( m_listeners, 0, listeners, 0, found ); | |||||
| final int count = m_listeners.length - found - 1; | |||||
| System.arraycopy( m_listeners, found, listeners, found + 1, count ); | |||||
| m_listeners = listeners; | |||||
| } | |||||
| /** | |||||
| * Fire a projectStarted event. | |||||
| */ | |||||
| public void projectStarted( final String projectName ) | |||||
| { | |||||
| m_projectName = projectName; | |||||
| m_targetName = null; | |||||
| m_taskName = null; | |||||
| for( int i = 0; i < m_listeners.length; i++ ) | |||||
| { | |||||
| m_listeners[ i ].projectStarted( this ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Fire a projectFinished event. | |||||
| */ | |||||
| public void projectFinished( final String projectName ) | |||||
| { | |||||
| m_projectName = projectName; | |||||
| for( int i = 0; i < m_listeners.length; i++ ) | |||||
| { | |||||
| m_listeners[ i ].projectFinished( this ); | |||||
| } | |||||
| m_projectName = null; | |||||
| m_targetName = null; | |||||
| m_taskName = null; | |||||
| } | |||||
| /** | |||||
| * Fire a targetStarted event. | |||||
| */ | |||||
| public void targetStarted( final String projectName, final String targetName ) | |||||
| { | |||||
| m_projectName = projectName; | |||||
| m_targetName = targetName; | |||||
| m_taskName = null; | |||||
| for( int i = 0; i < m_listeners.length; i++ ) | |||||
| { | |||||
| m_listeners[ i ].targetStarted( this ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Fire a targetFinished event. | |||||
| */ | |||||
| public void targetFinished() | |||||
| { | |||||
| for( int i = 0; i < m_listeners.length; i++ ) | |||||
| { | |||||
| m_listeners[ i ].targetFinished( this ); | |||||
| } | |||||
| m_targetName = null; | |||||
| m_taskName = null; | |||||
| } | |||||
| /** | |||||
| * Fire a targetStarted event. | |||||
| */ | |||||
| public void taskStarted( final String taskName ) | |||||
| { | |||||
| m_taskName = taskName; | |||||
| for( int i = 0; i < m_listeners.length; i++ ) | |||||
| { | |||||
| m_listeners[ i ].taskStarted( this ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Fire a taskFinished event. | |||||
| */ | |||||
| public void taskFinished() | |||||
| { | |||||
| for( int i = 0; i < m_listeners.length; i++ ) | |||||
| { | |||||
| m_listeners[ i ].taskFinished( this ); | |||||
| } | |||||
| m_taskName = null; | |||||
| } | |||||
| /** | |||||
| * Fire a log event. | |||||
| * | |||||
| * @param message the log message | |||||
| */ | |||||
| public void log( String message, Throwable throwable ) | |||||
| { | |||||
| m_message = message; | |||||
| m_throwable = throwable; | |||||
| try | |||||
| { | |||||
| for( int i = 0; i < m_listeners.length; i++ ) | |||||
| { | |||||
| m_listeners[ i ].log( this ); | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| m_message = null; | |||||
| m_throwable = null; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Returns the message. | |||||
| */ | |||||
| public String getMessage() | |||||
| { | |||||
| return m_message; | |||||
| } | |||||
| /** | |||||
| * Returns the error that occurred. | |||||
| */ | |||||
| public Throwable getThrowable() | |||||
| { | |||||
| return m_throwable; | |||||
| } | |||||
| /** | |||||
| * Returns the name of the task. | |||||
| */ | |||||
| public String getTaskName() | |||||
| { | |||||
| return m_taskName; | |||||
| } | |||||
| /** | |||||
| * Returns the name of the target. | |||||
| */ | |||||
| public String getTargetName() | |||||
| { | |||||
| return m_targetName; | |||||
| } | |||||
| /** | |||||
| * Returns the name of the project. | |||||
| */ | |||||
| public String getProjectName() | |||||
| { | |||||
| return m_projectName; | |||||
| } | |||||
| } | |||||
| @@ -1,19 +0,0 @@ | |||||
| no-read.error=Unable to read library at {0}. | |||||
| no-library.error=Unable to locate Type Library {0}. | |||||
| no-deploy.error=Error deploying type library {0} at {1}. | |||||
| bad-deployer-config.error=Error configuring deployer. | |||||
| bad-frame.error=Error setting up ExecutionFrame. | |||||
| no-project.error=Project {0} not found. | |||||
| no-target.error=Target {0} not found. | |||||
| exec-target.notice=Executing project {0}, target {1}. | |||||
| exec-task.notice=Executing task {0}. | |||||
| target-dependency-cycle.error=Cycle in dependencies for target {0}. | |||||
| #DefaultTaskContext | |||||
| unknown-prop.error=Unknown property {0}. | |||||
| bad-property.error=Property {0} must have a value of type {1}. | |||||
| bad-property-name.error=Invalid property name. | |||||
| null-resolved-value.error=Value "{0}" resolved to null. | |||||
| bad-resolve.error=Unable to resolve value "{0}". | |||||
| bad-find-service.error=Could not find service "{0}". | |||||
| bad-service-class.error=Find service "{0}" but it was of type {1} where it was expected to be of type {2}. | |||||
| @@ -1,85 +0,0 @@ | |||||
| /* | |||||
| * 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.components.workspace; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| import org.apache.myrmidon.frontends.AbstractLogger; | |||||
| /** | |||||
| * A logger that just routes the messages to the ProjectListenerSupport. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| final class RoutingLogger | |||||
| extends AbstractLogger | |||||
| implements Logger | |||||
| { | |||||
| /** | |||||
| * The endpoint of all the logging messages. | |||||
| */ | |||||
| private final ProjectListenerSupport m_listenerSupport; | |||||
| /** | |||||
| * A wrapped logger that is used to determine which message types are | |||||
| * enabled. | |||||
| */ | |||||
| private final Logger m_logger; | |||||
| /** | |||||
| * Create a Logger that routes messages at specified level | |||||
| * to specified support. | |||||
| * | |||||
| * @todo Use something other than a logger to figure out which messages | |||||
| * are enabled. | |||||
| */ | |||||
| public RoutingLogger( final Logger logger, | |||||
| final ProjectListenerSupport listenerSupport ) | |||||
| { | |||||
| m_listenerSupport = listenerSupport; | |||||
| m_logger = logger; | |||||
| } | |||||
| public boolean isDebugEnabled() | |||||
| { | |||||
| return m_logger.isDebugEnabled(); | |||||
| } | |||||
| public boolean isInfoEnabled() | |||||
| { | |||||
| return m_logger.isInfoEnabled(); | |||||
| } | |||||
| public boolean isWarnEnabled() | |||||
| { | |||||
| return m_logger.isWarnEnabled(); | |||||
| } | |||||
| public boolean isErrorEnabled() | |||||
| { | |||||
| return m_logger.isErrorEnabled(); | |||||
| } | |||||
| public boolean isFatalErrorEnabled() | |||||
| { | |||||
| return m_logger.isFatalErrorEnabled(); | |||||
| } | |||||
| public Logger getChildLogger( final String name ) | |||||
| { | |||||
| return new RoutingLogger( m_logger.getChildLogger( name ), m_listenerSupport ); | |||||
| } | |||||
| /** | |||||
| * Utility method to output messages. | |||||
| */ | |||||
| protected void output( final String message, final Throwable throwable ) | |||||
| { | |||||
| m_listenerSupport.log( message, throwable ); | |||||
| } | |||||
| } | |||||
| @@ -1,34 +0,0 @@ | |||||
| /* | |||||
| * 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.components.workspace; | |||||
| /** | |||||
| * An enumerated type that represents the dependency traversal state of a | |||||
| * target. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| final class TargetState | |||||
| { | |||||
| private TargetState() | |||||
| { | |||||
| } | |||||
| /** Target has not been started. */ | |||||
| public static final TargetState NOT_STARTED = new TargetState(); | |||||
| /** | |||||
| * Target has been started, and the dependencies of the target are being | |||||
| * traversed. | |||||
| */ | |||||
| public static final TargetState TRAVERSING = new TargetState(); | |||||
| /** Target has been completed. */ | |||||
| public static final TargetState FINISHED = new TargetState(); | |||||
| } | |||||
| @@ -1,167 +0,0 @@ | |||||
| /* | |||||
| * 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.frontends; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| /** | |||||
| * A partial logger implementation. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public abstract class AbstractLogger | |||||
| implements Logger | |||||
| { | |||||
| public static final int LEVEL_DEBUG = 0; | |||||
| public static final int LEVEL_INFO = 1; | |||||
| public static final int LEVEL_WARN = 2; | |||||
| public static final int LEVEL_ERROR = 3; | |||||
| public static final int LEVEL_FATAL = 4; | |||||
| /** | |||||
| * Log a debug message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void debug( final String message ) | |||||
| { | |||||
| if( isDebugEnabled() ) | |||||
| { | |||||
| output( message, null ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a debug message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void debug( final String message, final Throwable throwable ) | |||||
| { | |||||
| if( isDebugEnabled() ) | |||||
| { | |||||
| output( message, throwable ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a info message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void info( final String message ) | |||||
| { | |||||
| if( isInfoEnabled() ) | |||||
| { | |||||
| output( message, null ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a info message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void info( final String message, final Throwable throwable ) | |||||
| { | |||||
| if( isInfoEnabled() ) | |||||
| { | |||||
| output( message, throwable ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a warn message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void warn( final String message ) | |||||
| { | |||||
| if( isWarnEnabled() ) | |||||
| { | |||||
| output( message, null ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a warn message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void warn( final String message, final Throwable throwable ) | |||||
| { | |||||
| if( isWarnEnabled() ) | |||||
| { | |||||
| output( message, throwable ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a error message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void error( final String message ) | |||||
| { | |||||
| if( isErrorEnabled() ) | |||||
| { | |||||
| output( message, null ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a error message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void error( final String message, final Throwable throwable ) | |||||
| { | |||||
| if( isErrorEnabled() ) | |||||
| { | |||||
| output( message, throwable ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a fatalError message. | |||||
| * | |||||
| * @param message the message | |||||
| */ | |||||
| public void fatalError( final String message ) | |||||
| { | |||||
| if( isFatalErrorEnabled() ) | |||||
| { | |||||
| output( message, null ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Log a fatalError message. | |||||
| * | |||||
| * @param message the message | |||||
| * @param throwable the throwable | |||||
| */ | |||||
| public void fatalError( final String message, final Throwable throwable ) | |||||
| { | |||||
| if( isFatalErrorEnabled() ) | |||||
| { | |||||
| output( message, throwable ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Utility method to output messages. | |||||
| */ | |||||
| protected abstract void output( final String message, | |||||
| final Throwable throwable ); | |||||
| } | |||||
| @@ -1,124 +0,0 @@ | |||||
| /* | |||||
| * 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.frontends; | |||||
| import org.apache.avalon.framework.ExceptionUtil; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| /** | |||||
| * A basic logger that just prints out messages to <code>System.out</code>. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class BasicLogger | |||||
| extends AbstractLogger | |||||
| implements Logger | |||||
| { | |||||
| /** | |||||
| * The string prefixed to all log messages. | |||||
| */ | |||||
| private final String m_prefix; | |||||
| /** | |||||
| * The level at which messages start becoming logged. | |||||
| */ | |||||
| private final int m_logLevel; | |||||
| /** | |||||
| * Create a logger that has specified prefix and is logging | |||||
| * at specified level. | |||||
| */ | |||||
| public BasicLogger( final String prefix, final int logLevel ) | |||||
| { | |||||
| m_prefix = prefix; | |||||
| m_logLevel = logLevel; | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "debug" will be logged. | |||||
| * | |||||
| * @return true if "debug" messages will be logged | |||||
| */ | |||||
| public boolean isDebugEnabled() | |||||
| { | |||||
| return m_logLevel <= LEVEL_DEBUG; | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "info" will be logged. | |||||
| * | |||||
| * @return true if "info" messages will be logged | |||||
| */ | |||||
| public boolean isInfoEnabled() | |||||
| { | |||||
| return m_logLevel <= LEVEL_INFO; | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "warn" will be logged. | |||||
| * | |||||
| * @return true if "warn" messages will be logged | |||||
| */ | |||||
| public boolean isWarnEnabled() | |||||
| { | |||||
| return m_logLevel <= LEVEL_WARN; | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "error" will be logged. | |||||
| * | |||||
| * @return true if "error" messages will be logged | |||||
| */ | |||||
| public boolean isErrorEnabled() | |||||
| { | |||||
| return m_logLevel <= LEVEL_ERROR; | |||||
| } | |||||
| /** | |||||
| * Determine if messages of priority "fatalError" will be logged. | |||||
| * | |||||
| * @return true if "fatalError" messages will be logged | |||||
| */ | |||||
| public boolean isFatalErrorEnabled() | |||||
| { | |||||
| return m_logLevel <= LEVEL_FATAL; | |||||
| } | |||||
| /** | |||||
| * Create a new child logger. | |||||
| * The name of the child logger is [current-loggers-name].[passed-in-name] | |||||
| * | |||||
| * @param name the subname of this logger | |||||
| * @return the new logger | |||||
| * @exception IllegalArgumentException if name has an empty element name | |||||
| */ | |||||
| public Logger getChildLogger( final String name ) | |||||
| { | |||||
| return new BasicLogger( m_prefix + "." + name, m_logLevel ); | |||||
| } | |||||
| /** | |||||
| * Utility method to output messages. | |||||
| */ | |||||
| protected void output( final String message, final Throwable throwable ) | |||||
| { | |||||
| final StringBuffer sb = new StringBuffer( m_prefix ); | |||||
| if( null != message ) | |||||
| { | |||||
| sb.append( message ); | |||||
| } | |||||
| System.out.println( sb ); | |||||
| if( null != throwable ) | |||||
| { | |||||
| final String stackTrace = ExceptionUtil.printStackTrace( throwable, 8, true, true ); | |||||
| System.out.println( stackTrace ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,477 +0,0 @@ | |||||
| /* | |||||
| * 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.frontends; | |||||
| import java.io.BufferedReader; | |||||
| import java.io.File; | |||||
| import java.io.InputStreamReader; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| import org.apache.avalon.excalibur.cli.CLArgsParser; | |||||
| import org.apache.avalon.excalibur.cli.CLOption; | |||||
| import org.apache.avalon.excalibur.cli.CLOptionDescriptor; | |||||
| import org.apache.avalon.excalibur.cli.CLUtil; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.CascadingException; | |||||
| import org.apache.avalon.framework.ExceptionUtil; | |||||
| import org.apache.myrmidon.Constants; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.interfaces.executor.Executor; | |||||
| /** | |||||
| * The class to kick the tires and light the fires. | |||||
| * Starts myrmidon, loads ProjectBuilder, builds project then uses ProjectManager | |||||
| * to run project. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class CLIMain | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( CLIMain.class ); | |||||
| //defines for the Command Line options | |||||
| private static final int HELP_OPT = 'h'; | |||||
| private static final int QUIET_OPT = 'q'; | |||||
| private static final int VERBOSE_OPT = 'v'; | |||||
| private static final int FILE_OPT = 'f'; | |||||
| private static final int LOG_LEVEL_OPT = 'l'; | |||||
| private static final int DEFINE_OPT = 'D'; | |||||
| private static final int BUILDER_PARAM_OPT = 'B'; | |||||
| private static final int NO_PREFIX_OPT = 'p'; | |||||
| private static final int VERSION_OPT = 1; | |||||
| private static final int LISTENER_OPT = 2; | |||||
| private static final int TASKLIB_DIR_OPT = 5; | |||||
| private static final int EXTLIB_DIR_OPT = 6; | |||||
| private static final int INCREMENTAL_OPT = 7; | |||||
| private static final int HOME_DIR_OPT = 8; | |||||
| private static final int DRY_RUN_OPT = 9; | |||||
| private static final int DEBUG_OPT = 10; | |||||
| private static final int TYPE_OPT = 11; | |||||
| //incompatable options for info options | |||||
| private static final int[] INFO_OPT_INCOMPAT = new int[] | |||||
| { | |||||
| HELP_OPT, QUIET_OPT, VERBOSE_OPT, FILE_OPT, | |||||
| LOG_LEVEL_OPT, BUILDER_PARAM_OPT, NO_PREFIX_OPT, | |||||
| VERSION_OPT, LISTENER_OPT, TASKLIB_DIR_OPT, EXTLIB_DIR_OPT, | |||||
| INCREMENTAL_OPT, HOME_DIR_OPT, DRY_RUN_OPT, TYPE_OPT | |||||
| }; | |||||
| //incompatable options for other logging options | |||||
| private static final int[] LOG_OPT_INCOMPAT = new int[] | |||||
| { | |||||
| QUIET_OPT, VERBOSE_OPT, LOG_LEVEL_OPT, DEBUG_OPT | |||||
| }; | |||||
| //incompatible options for listener options | |||||
| private static final int[] LISTENER_OPT_INCOMPAT = new int[] | |||||
| { | |||||
| LISTENER_OPT, NO_PREFIX_OPT | |||||
| }; | |||||
| ///List of targets supplied on command line to execute | |||||
| private ArrayList m_targets = new ArrayList(); | |||||
| ///Determine whether tasks are actually executed | |||||
| private boolean m_dryRun = false; | |||||
| ///Enables incremental mode | |||||
| private boolean m_incremental; | |||||
| ///The launcher | |||||
| private EmbeddedAnt m_embedded = new EmbeddedAnt(); | |||||
| ///Log level to use | |||||
| private static int m_priority = BasicLogger.LEVEL_WARN; | |||||
| /** | |||||
| * Main entry point called to run standard Myrmidon. | |||||
| * | |||||
| * @param args the args | |||||
| */ | |||||
| public static void main( final String[] args ) | |||||
| { | |||||
| final Map properties = new HashMap(); | |||||
| properties.put( "myrmidon.home", new File( "." ) ); | |||||
| main( properties, args ); | |||||
| } | |||||
| /** | |||||
| * Main entry point called to run standard Myrmidon. | |||||
| * | |||||
| * @param args the args | |||||
| */ | |||||
| public static void main( final Map properties, final String[] args ) | |||||
| { | |||||
| int exitCode = 0; | |||||
| final CLIMain main = new CLIMain(); | |||||
| try | |||||
| { | |||||
| main.execute( properties, args ); | |||||
| } | |||||
| catch( final Throwable throwable ) | |||||
| { | |||||
| main.reportError( throwable ); | |||||
| exitCode = -1; | |||||
| } | |||||
| finally | |||||
| { | |||||
| System.exit( exitCode ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Display usage report. | |||||
| * | |||||
| */ | |||||
| private void usage( final CLOptionDescriptor[] options ) | |||||
| { | |||||
| System.out.println( "ant [options] [targets]" ); | |||||
| System.out.println( "\tAvailable options:" ); | |||||
| System.out.println( CLUtil.describeOptions( options ) ); | |||||
| } | |||||
| /** | |||||
| * Initialise the options for command line parser. | |||||
| */ | |||||
| private CLOptionDescriptor[] createCLOptions() | |||||
| { | |||||
| //TODO: localise | |||||
| final CLOptionDescriptor[] options = { | |||||
| new CLOptionDescriptor( "help", | |||||
| CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
| HELP_OPT, | |||||
| REZ.getString( "help.opt" ), | |||||
| INFO_OPT_INCOMPAT ), | |||||
| new CLOptionDescriptor( "file", | |||||
| CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
| FILE_OPT, | |||||
| REZ.getString( "file.opt" ) ), | |||||
| new CLOptionDescriptor( "log-level", | |||||
| CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
| LOG_LEVEL_OPT, | |||||
| REZ.getString( "log-level.opt" ), | |||||
| LOG_OPT_INCOMPAT ), | |||||
| new CLOptionDescriptor( "quiet", | |||||
| CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
| QUIET_OPT, | |||||
| REZ.getString( "quiet.opt" ), | |||||
| LOG_OPT_INCOMPAT ), | |||||
| new CLOptionDescriptor( "verbose", | |||||
| CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
| VERBOSE_OPT, | |||||
| REZ.getString( "verbose.opt" ), | |||||
| LOG_OPT_INCOMPAT ), | |||||
| new CLOptionDescriptor( "debug", | |||||
| CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
| DEBUG_OPT, | |||||
| REZ.getString( "debug.opt" ), | |||||
| LOG_OPT_INCOMPAT ), | |||||
| new CLOptionDescriptor( "listener", | |||||
| CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
| LISTENER_OPT, | |||||
| REZ.getString( "listener.opt" ), | |||||
| LISTENER_OPT_INCOMPAT ), | |||||
| new CLOptionDescriptor( "noprefix", | |||||
| CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
| NO_PREFIX_OPT, | |||||
| REZ.getString( "noprefix.opt" ), | |||||
| LISTENER_OPT_INCOMPAT ), | |||||
| new CLOptionDescriptor( "version", | |||||
| CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
| VERSION_OPT, | |||||
| REZ.getString( "version.opt" ), | |||||
| INFO_OPT_INCOMPAT ), | |||||
| new CLOptionDescriptor( "antlib-path", | |||||
| CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
| TASKLIB_DIR_OPT, | |||||
| REZ.getString( "tasklib.opt" ) ), | |||||
| new CLOptionDescriptor( "ext-path", | |||||
| CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
| EXTLIB_DIR_OPT, | |||||
| REZ.getString( "extlib.opt" ) ), | |||||
| new CLOptionDescriptor( "incremental", | |||||
| CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
| INCREMENTAL_OPT, | |||||
| REZ.getString( "incremental.opt" ) ), | |||||
| new CLOptionDescriptor( "ant-home", | |||||
| CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
| HOME_DIR_OPT, | |||||
| REZ.getString( "home.opt" ) ), | |||||
| new CLOptionDescriptor( "define", | |||||
| CLOptionDescriptor.ARGUMENTS_REQUIRED_2, | |||||
| DEFINE_OPT, | |||||
| REZ.getString( "define.opt" ), | |||||
| new int[ 0 ] ), | |||||
| new CLOptionDescriptor( "builder-parameter", | |||||
| CLOptionDescriptor.ARGUMENTS_REQUIRED_2, | |||||
| BUILDER_PARAM_OPT, | |||||
| REZ.getString( "build.opt" ) ), | |||||
| new CLOptionDescriptor( "dry-run", | |||||
| CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
| DRY_RUN_OPT, | |||||
| REZ.getString( "dry-run.opt" ) ), | |||||
| new CLOptionDescriptor( "type", | |||||
| CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
| TYPE_OPT, | |||||
| REZ.getString( "type.opt" ) ) | |||||
| }; | |||||
| return options; | |||||
| } | |||||
| private boolean parseCommandLineOptions( final String[] args ) | |||||
| throws Exception | |||||
| { | |||||
| final CLOptionDescriptor[] options = createCLOptions(); | |||||
| final CLArgsParser parser = new CLArgsParser( args, options ); | |||||
| if( null != parser.getErrorString() ) | |||||
| { | |||||
| final String message = REZ.getString( "error-message", parser.getErrorString() ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| final List clOptions = parser.getArguments(); | |||||
| final int size = clOptions.size(); | |||||
| for( int i = 0; i < size; i++ ) | |||||
| { | |||||
| final CLOption option = (CLOption)clOptions.get( i ); | |||||
| switch( option.getId() ) | |||||
| { | |||||
| case HELP_OPT: | |||||
| usage( options ); | |||||
| return false; | |||||
| case VERSION_OPT: | |||||
| System.out.println( Constants.BUILD_DESCRIPTION ); | |||||
| return false; | |||||
| case HOME_DIR_OPT: | |||||
| m_embedded.setEmbeddorProperty( "myrmidon.home", option.getArgument() ); | |||||
| break; | |||||
| case TASKLIB_DIR_OPT: | |||||
| m_embedded.setEmbeddorProperty( "myrmidon.antlib.path", option.getArgument() ); | |||||
| break; | |||||
| case EXTLIB_DIR_OPT: | |||||
| m_embedded.setEmbeddorProperty( "myrmidon.ext.path", option.getArgument() ); | |||||
| break; | |||||
| case LOG_LEVEL_OPT: | |||||
| m_priority = mapLogLevel( option.getArgument() ); | |||||
| break; | |||||
| case VERBOSE_OPT: | |||||
| m_priority = BasicLogger.LEVEL_INFO; | |||||
| break; | |||||
| case DEBUG_OPT: | |||||
| m_priority = BasicLogger.LEVEL_DEBUG; | |||||
| break; | |||||
| case QUIET_OPT: | |||||
| m_priority = BasicLogger.LEVEL_ERROR; | |||||
| break; | |||||
| case INCREMENTAL_OPT: | |||||
| m_incremental = true; | |||||
| break; | |||||
| case FILE_OPT: | |||||
| m_embedded.setProjectFile( option.getArgument() ); | |||||
| break; | |||||
| case LISTENER_OPT: | |||||
| m_embedded.setProjectListener( option.getArgument() ); | |||||
| break; | |||||
| case NO_PREFIX_OPT: | |||||
| m_embedded.setProjectListener( "noprefix" ); | |||||
| break; | |||||
| case DEFINE_OPT: | |||||
| m_embedded.setWorkspaceProperty( option.getArgument( 0 ), option.getArgument( 1 ) ); | |||||
| break; | |||||
| case BUILDER_PARAM_OPT: | |||||
| m_embedded.setBuilderProperty( option.getArgument( 0 ), option.getArgument( 1 ) ); | |||||
| break; | |||||
| case DRY_RUN_OPT: | |||||
| m_dryRun = true; | |||||
| break; | |||||
| case TYPE_OPT: | |||||
| m_embedded.setProjectType( option.getArgument( 0 ) ); | |||||
| break; | |||||
| case 0: | |||||
| m_targets.add( option.getArgument() ); | |||||
| break; | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| private void execute( final Map properties, final String[] args ) | |||||
| throws Exception | |||||
| { | |||||
| try | |||||
| { | |||||
| // Set system properties set up by launcher | |||||
| m_embedded.setHomeDirectory( (File)properties.get( "myrmidon.home" ) ); | |||||
| // Command line | |||||
| if( !parseCommandLineOptions( args ) ) | |||||
| { | |||||
| return; | |||||
| } | |||||
| // Setup logging | |||||
| final BasicLogger logger = new BasicLogger( "[myrmidon] ", m_priority ); | |||||
| m_embedded.enableLogging( logger ); | |||||
| if( m_dryRun ) | |||||
| { | |||||
| m_embedded.setEmbeddorProperty( Executor.ROLE, | |||||
| "org.apache.myrmidon.components.executor.PrintingExecutor" ); | |||||
| } | |||||
| // Set the common classloader | |||||
| final ClassLoader sharedClassLoader = (ClassLoader)properties.get( "myrmidon.shared.classloader" ); | |||||
| m_embedded.setSharedClassLoader( sharedClassLoader ); | |||||
| //loop over build if we are in incremental mode.. | |||||
| if( !m_incremental ) | |||||
| { | |||||
| executeBuild(); | |||||
| } | |||||
| else | |||||
| { | |||||
| executeIncrementalBuild(); | |||||
| } | |||||
| } | |||||
| catch( final Exception e ) | |||||
| { | |||||
| final String message = REZ.getString( "build-failed.error" ); | |||||
| throw new CascadingException( message, e ); | |||||
| } | |||||
| finally | |||||
| { | |||||
| m_embedded.stop(); | |||||
| } | |||||
| } | |||||
| private void executeIncrementalBuild() | |||||
| throws Exception | |||||
| { | |||||
| BufferedReader reader = null; | |||||
| while( true ) | |||||
| { | |||||
| try | |||||
| { | |||||
| executeBuild(); | |||||
| } | |||||
| catch( final TaskException te ) | |||||
| { | |||||
| reportError( te ); | |||||
| } | |||||
| final String message = REZ.getString( "repeat.notice" ); | |||||
| System.out.println( message ); | |||||
| if( null == reader ) | |||||
| { | |||||
| reader = new BufferedReader( new InputStreamReader( System.in ) ); | |||||
| } | |||||
| String line = reader.readLine(); | |||||
| if( line.equalsIgnoreCase( "no" ) ) | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| private void executeBuild() throws Exception | |||||
| { | |||||
| //actually do the build ... | |||||
| final String[] targets = (String[])m_targets.toArray( new String[ m_targets.size() ] ); | |||||
| m_embedded.executeTargets( targets ); | |||||
| } | |||||
| /** | |||||
| * Builds the error message for an exception | |||||
| */ | |||||
| private void reportError( final Throwable throwable ) | |||||
| { | |||||
| // Build the message | |||||
| final String message; | |||||
| if( m_priority <= BasicLogger.LEVEL_INFO ) | |||||
| { | |||||
| // Verbose mode - include the stack traces | |||||
| message = ExceptionUtil.printStackTrace( throwable, 8, true, true ); | |||||
| } | |||||
| else | |||||
| { | |||||
| // Build the message | |||||
| final StringBuffer buffer = new StringBuffer(); | |||||
| buffer.append( throwable.getMessage() ); | |||||
| for( Throwable current = ExceptionUtil.getCause( throwable, true ); | |||||
| current != null; | |||||
| current = ExceptionUtil.getCause( current, true ) ) | |||||
| { | |||||
| final String causeMessage = REZ.getString( "cause.error", current.getMessage() ); | |||||
| buffer.append( causeMessage ); | |||||
| } | |||||
| message = buffer.toString(); | |||||
| } | |||||
| // Write the message out | |||||
| System.err.println( message ); | |||||
| } | |||||
| /** | |||||
| * Sets the log level. | |||||
| */ | |||||
| private int mapLogLevel( final String logLevel ) | |||||
| throws Exception | |||||
| { | |||||
| final String logLevelCapitalized = logLevel.toUpperCase(); | |||||
| if( "DEBUG".equals( logLevelCapitalized ) ) | |||||
| { | |||||
| return BasicLogger.LEVEL_DEBUG; | |||||
| } | |||||
| else if( "VERBOSE".equals( logLevelCapitalized ) ) | |||||
| { | |||||
| return BasicLogger.LEVEL_INFO; | |||||
| } | |||||
| else if( "INFO".equals( logLevelCapitalized ) ) | |||||
| { | |||||
| return BasicLogger.LEVEL_WARN; | |||||
| } | |||||
| else if( "WARN".equals( logLevelCapitalized ) ) | |||||
| { | |||||
| return BasicLogger.LEVEL_ERROR; | |||||
| } | |||||
| else if( "ERROR".equals( logLevelCapitalized ) ) | |||||
| { | |||||
| return BasicLogger.LEVEL_FATAL; | |||||
| } | |||||
| else | |||||
| { | |||||
| final String message = REZ.getString( "bad-loglevel.error", logLevel ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,420 +0,0 @@ | |||||
| /* | |||||
| * 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.frontends; | |||||
| import java.io.File; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.excalibur.io.FileUtil; | |||||
| import org.apache.avalon.excalibur.util.StringUtil; | |||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.activity.Initializable; | |||||
| import org.apache.avalon.framework.activity.Startable; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.avalon.framework.context.Contextualizable; | |||||
| import org.apache.avalon.framework.context.DefaultContext; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.parameters.Parameters; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.interfaces.embeddor.Embeddor; | |||||
| import org.apache.myrmidon.interfaces.model.Project; | |||||
| import org.apache.myrmidon.interfaces.workspace.Workspace; | |||||
| import org.apache.myrmidon.listeners.ProjectListener; | |||||
| /** | |||||
| * A utility class, that takes care of launching Myrmidon, and building and | |||||
| * executing a project. | |||||
| * | |||||
| * <p>To use this class, create an instance and configure. To execute | |||||
| * targets in a project, use the {@link #executeTargets} method. This can | |||||
| * be done one or more times. Finally, call the {@link #stop} method to | |||||
| * clean-up. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class EmbeddedAnt | |||||
| extends AbstractLogEnabled | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( EmbeddedAnt.class ); | |||||
| private static final String DEFAULT_EMBEDDOR_CLASS = | |||||
| "org.apache.myrmidon.components.embeddor.DefaultEmbeddor"; | |||||
| private final ArrayList m_listeners = new ArrayList(); | |||||
| private final Parameters m_builderProps = new Parameters(); | |||||
| private final Map m_embeddorParameters = new HashMap(); | |||||
| private final Map m_workspaceProperties = new HashMap(); | |||||
| private String m_projectFile = "build.ant"; | |||||
| private Project m_project; | |||||
| private String m_listenerName = "default"; | |||||
| private ClassLoader m_sharedClassLoader; | |||||
| private Embeddor m_embeddor; | |||||
| private File m_homeDir; | |||||
| private String m_projectType; | |||||
| /** | |||||
| * Sets the Myrmidon home directory. Default is to use the current | |||||
| * directory. | |||||
| * | |||||
| * @todo Autodetect myrmidon home, rather than using current directory | |||||
| * as the default (which is a dud default). | |||||
| */ | |||||
| public void setHomeDirectory( final File homeDir ) | |||||
| { | |||||
| m_homeDir = homeDir.getAbsoluteFile(); | |||||
| } | |||||
| /** | |||||
| * Sets the project file to execute. Default is 'build.ant'. | |||||
| */ | |||||
| public void setProjectFile( final String projectFile ) | |||||
| { | |||||
| m_projectFile = projectFile; | |||||
| m_project = null; | |||||
| } | |||||
| /** | |||||
| * Sets the project file type. Ignored if {@link #setProject} is used. | |||||
| * Set to null to use the default project type. | |||||
| */ | |||||
| public void setProjectType( final String projectType ) | |||||
| { | |||||
| m_projectType = projectType; | |||||
| } | |||||
| /** | |||||
| * Sets the project to execute. This method can be used instead of | |||||
| * {@link #setProjectFile}, for projects models that are built | |||||
| * programmatically. | |||||
| */ | |||||
| public void setProject( final Project project ) | |||||
| { | |||||
| m_projectFile = null; | |||||
| m_project = project; | |||||
| } | |||||
| /** | |||||
| * Sets the name of the project listener to use. Set to null to disable | |||||
| * the project listener. | |||||
| */ | |||||
| public void setProjectListener( final String listener ) | |||||
| { | |||||
| m_listenerName = listener; | |||||
| } | |||||
| /** | |||||
| * Adds a project listener. | |||||
| */ | |||||
| public void addProjectListener( final ProjectListener listener ) | |||||
| { | |||||
| m_listeners.add( listener ); | |||||
| } | |||||
| /** | |||||
| * Sets a workspace property. These are inherited by all projects executed | |||||
| * by this embeddor. | |||||
| */ | |||||
| public void setWorkspaceProperty( final String name, final Object value ) | |||||
| { | |||||
| m_workspaceProperties.put( name, value ); | |||||
| } | |||||
| /** | |||||
| * Sets a project builder property. These are used by the project builder | |||||
| * when it is parsing the project file. | |||||
| */ | |||||
| public void setBuilderProperty( final String name, final Object value ) | |||||
| { | |||||
| // TODO - Make properties Objects, not Strings | |||||
| m_builderProps.setParameter( name, value.toString() ); | |||||
| } | |||||
| /** | |||||
| * Sets a task engine property. These are used to configure the task engine. | |||||
| * | |||||
| * @todo Make this method actually work with objects... | |||||
| */ | |||||
| public void setEmbeddorProperty( final String name, final Object value ) | |||||
| { | |||||
| m_embeddorParameters.put( name, value.toString() ); | |||||
| } | |||||
| /** | |||||
| * Sets the shared classloader, which is used as the parent classloader | |||||
| * for all antlibs. Default is to use the context classloader. | |||||
| */ | |||||
| public void setSharedClassLoader( final ClassLoader classLoader ) | |||||
| { | |||||
| m_sharedClassLoader = classLoader; | |||||
| } | |||||
| /** | |||||
| * Executes a set of targets in the project. This method may be called | |||||
| * multiple times. | |||||
| */ | |||||
| public void executeTargets( final String[] targets ) throws Exception | |||||
| { | |||||
| Map embeddorParameters = new HashMap( m_embeddorParameters ); | |||||
| setupPaths( embeddorParameters ); | |||||
| if( m_sharedClassLoader != null ) | |||||
| { | |||||
| embeddorParameters.put( "myrmidon.shared.classloader", m_sharedClassLoader ); | |||||
| } | |||||
| // Prepare the embeddor, and project model | |||||
| final Embeddor embeddor = prepareEmbeddor( embeddorParameters ); | |||||
| final Project project = prepareProjectModel( embeddor ); | |||||
| // Create a new workspace | |||||
| final Workspace workspace = embeddor.createWorkspace( m_workspaceProperties ); | |||||
| prepareListeners( embeddor, workspace ); | |||||
| //execute the project | |||||
| executeTargets( workspace, project, targets ); | |||||
| } | |||||
| /** | |||||
| * Shuts down the task engine, after the project has been executed. | |||||
| */ | |||||
| public void stop() throws Exception | |||||
| { | |||||
| try | |||||
| { | |||||
| if( m_embeddor != null ) | |||||
| { | |||||
| if( m_embeddor instanceof Startable ) | |||||
| { | |||||
| ( (Startable)m_embeddor ).stop(); | |||||
| } | |||||
| if( m_embeddor instanceof Disposable ) | |||||
| { | |||||
| ( (Disposable)m_embeddor ).dispose(); | |||||
| } | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| m_embeddor = null; | |||||
| m_project = null; | |||||
| m_listeners.clear(); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Actually do the build. | |||||
| */ | |||||
| private void executeTargets( final Workspace workspace, | |||||
| final Project project, | |||||
| final String[] targets ) | |||||
| throws TaskException | |||||
| { | |||||
| //if we didn't specify a target, then choose default | |||||
| if( targets == null || targets.length == 0 ) | |||||
| { | |||||
| workspace.executeProject( project, project.getDefaultTargetName() ); | |||||
| } | |||||
| else | |||||
| { | |||||
| for( int i = 0; i < targets.length; i++ ) | |||||
| { | |||||
| workspace.executeProject( project, targets[ i ] ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Make sure myrmidon home directory has been specified, and is a | |||||
| * directory. Set the paths that the embeddor expects. | |||||
| */ | |||||
| private void setupPaths( Map parameters ) throws Exception | |||||
| { | |||||
| if( m_homeDir == null ) | |||||
| { | |||||
| m_homeDir = new File( "." ).getAbsoluteFile(); | |||||
| } | |||||
| checkDirectory( m_homeDir, "home-dir.name" ); | |||||
| parameters.put( "myrmidon.home", m_homeDir ); | |||||
| if( getLogger().isInfoEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( "homedir.notice", m_homeDir ); | |||||
| getLogger().info( message ); | |||||
| } | |||||
| // Build the lib path | |||||
| String path = (String)parameters.get( "myrmidon.lib.path" ); | |||||
| File[] dirs = buildPath( m_homeDir, path, "lib", "lib-dir.name" ); | |||||
| parameters.put( "myrmidon.lib.path", dirs ); | |||||
| // Build the antlib search path | |||||
| path = (String)parameters.get( "myrmidon.antlib.path" ); | |||||
| dirs = buildPath( m_homeDir, path, "ext", "task-lib-dir.name" ); | |||||
| parameters.put( "myrmidon.antlib.path", dirs ); | |||||
| // Build the extension search path | |||||
| path = (String)parameters.get( "myrmidon.ext.path" ); | |||||
| dirs = buildPath( m_homeDir, path, "ext", "ext-dir.name" ); | |||||
| parameters.put( "myrmidon.ext.path", dirs ); | |||||
| } | |||||
| /** | |||||
| * Prepares and returns the embeddor to use. | |||||
| */ | |||||
| private Embeddor prepareEmbeddor( final Map parameters ) | |||||
| throws Exception | |||||
| { | |||||
| if( m_embeddor == null ) | |||||
| { | |||||
| m_embeddor = createEmbeddor(); | |||||
| setupLogger( m_embeddor ); | |||||
| if( m_embeddor instanceof Contextualizable ) | |||||
| { | |||||
| final Context context = new DefaultContext( parameters ); | |||||
| ( (Contextualizable)m_embeddor ).contextualize( context ); | |||||
| } | |||||
| if( m_embeddor instanceof Initializable ) | |||||
| { | |||||
| ( (Initializable)m_embeddor ).initialize(); | |||||
| } | |||||
| if( m_embeddor instanceof Startable ) | |||||
| { | |||||
| ( (Startable)m_embeddor ).start(); | |||||
| } | |||||
| } | |||||
| return m_embeddor; | |||||
| } | |||||
| /** | |||||
| * Creates the embeddor. | |||||
| */ | |||||
| private Embeddor createEmbeddor() | |||||
| throws Exception | |||||
| { | |||||
| final Class clazz = Class.forName( DEFAULT_EMBEDDOR_CLASS ); | |||||
| return (Embeddor)clazz.newInstance(); | |||||
| } | |||||
| /** | |||||
| * Prepares and returns the project listener to use. | |||||
| */ | |||||
| private void prepareListeners( final Embeddor embeddor, | |||||
| final Workspace workspace ) | |||||
| throws Exception | |||||
| { | |||||
| if( m_listenerName != null ) | |||||
| { | |||||
| final ProjectListener listener = embeddor.createListener( m_listenerName ); | |||||
| workspace.addProjectListener( listener ); | |||||
| } | |||||
| final int count = m_listeners.size(); | |||||
| for( int i = 0; i < count; i++ ) | |||||
| { | |||||
| final ProjectListener listener = (ProjectListener)m_listeners.get( i ); | |||||
| workspace.addProjectListener( listener ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Prepares and returns the project model. | |||||
| */ | |||||
| private Project prepareProjectModel( final Embeddor embeddor ) throws Exception | |||||
| { | |||||
| if( m_project == null ) | |||||
| { | |||||
| final File buildFile = getProjectFile(); | |||||
| m_project = embeddor.createProject( buildFile.toString(), m_projectType, m_builderProps ); | |||||
| } | |||||
| return m_project; | |||||
| } | |||||
| /** | |||||
| * Locates the project file | |||||
| */ | |||||
| private File getProjectFile() throws Exception | |||||
| { | |||||
| final File projectFile = ( new File( m_projectFile ) ).getCanonicalFile(); | |||||
| if( !projectFile.isFile() ) | |||||
| { | |||||
| final String message = REZ.getString( "bad-file.error", projectFile ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| if( getLogger().isInfoEnabled() ) | |||||
| { | |||||
| final String message = REZ.getString( "buildfile.notice", projectFile ); | |||||
| getLogger().info( message ); | |||||
| } | |||||
| return projectFile; | |||||
| } | |||||
| /** | |||||
| * Resolve a directory relative to another base directory. | |||||
| */ | |||||
| private File[] buildPath( final File baseDir, | |||||
| final String path, | |||||
| final String defaultPath, | |||||
| final String name ) | |||||
| throws Exception | |||||
| { | |||||
| // Build the canonical list of files | |||||
| final ArrayList files = new ArrayList(); | |||||
| // Add the default path | |||||
| files.add( FileUtil.resolveFile( baseDir, defaultPath ) ); | |||||
| // Add the additional path | |||||
| if( path != null ) | |||||
| { | |||||
| final String[] split = StringUtil.split( path, File.pathSeparator ); | |||||
| for( int i = 0; i < split.length; i++ ) | |||||
| { | |||||
| final String s = split[ i ]; | |||||
| final File file = new File( s ).getAbsoluteFile(); | |||||
| files.add( file ); | |||||
| } | |||||
| } | |||||
| // Check each one | |||||
| for( int i = 0; i < files.size(); i++ ) | |||||
| { | |||||
| File file = (File)files.get( i ); | |||||
| checkDirectory( file, name ); | |||||
| } | |||||
| return (File[])files.toArray( new File[ files.size() ] ); | |||||
| } | |||||
| /** | |||||
| * Verify file is a directory else throw an exception. | |||||
| */ | |||||
| private void checkDirectory( final File file, final String name ) | |||||
| throws Exception | |||||
| { | |||||
| if( !file.exists() ) | |||||
| { | |||||
| final String nameStr = REZ.getString( name ); | |||||
| final String message = REZ.getString( "file-no-exist.error", nameStr, file ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| else if( !file.isDirectory() ) | |||||
| { | |||||
| final String nameStr = REZ.getString( name ); | |||||
| final String message = REZ.getString( "file-not-dir.error", nameStr, file ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,35 +0,0 @@ | |||||
| error-message=Error: {0}. | |||||
| help.opt=Display this help message. | |||||
| file.opt=Specify the build file. | |||||
| log-level.opt=Specify the verbosity level at which to log messages. (DEBUG|VERBOSE|INFO|WARN|ERROR). | |||||
| quiet.opt=Equivalent to --log-level=ERROR. | |||||
| verbose.opt=Equivalent to --log-level=VERBOSE. | |||||
| debug.opt=Equivalent to --log-level=DEBUG. | |||||
| listener.opt=Specify the listener for log events. | |||||
| noprefix.opt=Do not prefix output with the task name. Equivalent to --listener noprefix. | |||||
| version.opt=Display version. | |||||
| tasklib.opt=Specify the path to use to search for antlib libraries. | |||||
| extlib.opt=Specify the path to use to search for optional packages. | |||||
| incremental.opt=Run in incremental mode. | |||||
| home.opt=Specify Ant home directory. | |||||
| define.opt=Define a property (ie -Dfoo=var). | |||||
| build.opt=Define a builder parameter (ie -Bfoo=var). | |||||
| dry-run.opt=Do not execute tasks - just print them out. | |||||
| type.opt=Specify the project file type. | |||||
| file-no-exist.error={0} {1} does not exist. | |||||
| file-not-dir.error={0} {1} is not a directory. | |||||
| bad-file.error=File {0} is not a file or doesn't exist. | |||||
| bad-loglevel.error=Unknown log level - {0}. | |||||
| build-failed.error=BUILD FAILED. | |||||
| cause.error=\nReason: {0} | |||||
| repeat.notice=Continue ? (Enter no to stop) | |||||
| homedir.notice=Ant Home Directory: {0} | |||||
| buildfile.notice=Ant Build File: {0} | |||||
| home-dir.name=Ant home directory | |||||
| lib-dir.name=Library directory | |||||
| task-lib-dir.name=Antlib directory | |||||
| ext-dir.name=Extension directory | |||||
| @@ -1,56 +0,0 @@ | |||||
| /* | |||||
| * 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; | |||||
| /** | |||||
| * An exception thrown by a Myrmidon component. This is a convenience | |||||
| * class, which can be sub-classes to create exceptions for specific components. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class ComponentException | |||||
| extends Exception | |||||
| { | |||||
| /** | |||||
| * The Throwable that caused this exception to be thrown. | |||||
| */ | |||||
| private final Throwable m_throwable; | |||||
| /** | |||||
| * Constructs a non-cascaded exception. | |||||
| * | |||||
| * @param message The detail message for this exception. | |||||
| */ | |||||
| public ComponentException( final String message ) | |||||
| { | |||||
| this( message, null ); | |||||
| } | |||||
| /** | |||||
| * Constructs a cascaded exception. | |||||
| * | |||||
| * @param message The detail message for this exception. | |||||
| * @param throwable the root cause of the exception | |||||
| */ | |||||
| public ComponentException( final String message, final Throwable throwable ) | |||||
| { | |||||
| super( message ); | |||||
| m_throwable = throwable; | |||||
| } | |||||
| /** | |||||
| * Retrieve root cause of the exception. | |||||
| * | |||||
| * @return the root cause | |||||
| */ | |||||
| public final Throwable getCause() | |||||
| { | |||||
| return m_throwable; | |||||
| } | |||||
| } | |||||
| @@ -1,59 +0,0 @@ | |||||
| /* | |||||
| * 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.aspect; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.parameters.Parameters; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.aspects.AspectHandler; | |||||
| /** | |||||
| * Manage and propogate Aspects.. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface AspectManager | |||||
| extends AspectHandler | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = AspectManager.class.getName(); | |||||
| /** | |||||
| * @return The names of all AspectHandlers managed. | |||||
| */ | |||||
| String[] getNames(); | |||||
| /** | |||||
| * Dispatches aspect settings to the named AspectHandler. | |||||
| * @param name The name of the AspectHandler to recieve the settings. | |||||
| * @param parameters The parameter settings. | |||||
| * @param elements The nested Configuration settings. | |||||
| * @throws TaskException if the named AspectHandler doesn't exist, | |||||
| * or it cannot handle the settings. | |||||
| */ | |||||
| void dispatchAspectSettings( String name, Parameters parameters, Configuration[] elements ) | |||||
| throws TaskException; | |||||
| /** | |||||
| * Adds a named aspect handler to the manager. | |||||
| * @param name The name used to lookup the aspect handler. | |||||
| * @param handler The aspect handler to add. | |||||
| * @throws TaskException If an error occurs. | |||||
| */ | |||||
| void addAspectHandler( String name, AspectHandler handler ) | |||||
| throws TaskException; | |||||
| /** | |||||
| * Removes a named aspect handler from the manager. | |||||
| * @param name The name of the handler to remove. | |||||
| * @throws TaskException If the named handler doesn't exist. | |||||
| */ | |||||
| void removeAspectHandler( String name ) | |||||
| throws TaskException; | |||||
| } | |||||
| @@ -1,33 +0,0 @@ | |||||
| /* | |||||
| * 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.builder; | |||||
| import org.apache.myrmidon.interfaces.model.Project; | |||||
| /** | |||||
| * Interface implemented by components that build projects from sources. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * @ant:role shorthand="project-builder" | |||||
| */ | |||||
| public interface ProjectBuilder | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = ProjectBuilder.class.getName(); | |||||
| /** | |||||
| * build a project from source. | |||||
| * | |||||
| * @param source the project file path. | |||||
| * @return the constructed Project | |||||
| * @exception ProjectException if an error occurs | |||||
| */ | |||||
| Project build( String source ) | |||||
| throws ProjectException; | |||||
| } | |||||
| @@ -1,41 +0,0 @@ | |||||
| /* | |||||
| * 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.builder; | |||||
| import org.apache.myrmidon.interfaces.ComponentException; | |||||
| /** | |||||
| * A cascading exception thrown on a problem constructing a Project model. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class ProjectException | |||||
| extends ComponentException | |||||
| { | |||||
| /** | |||||
| * Constructs a non-cascaded exception. | |||||
| * | |||||
| * @param message The detail message for this exception. | |||||
| */ | |||||
| public ProjectException( final String message ) | |||||
| { | |||||
| super( message ); | |||||
| } | |||||
| /** | |||||
| * Constructs a cascaded exception. | |||||
| * | |||||
| * @param message The detail message for this exception. | |||||
| * @param throwable the root cause of the exception | |||||
| */ | |||||
| public ProjectException( final String message, final Throwable throwable ) | |||||
| { | |||||
| super( message, throwable ); | |||||
| } | |||||
| } | |||||
| @@ -1,41 +0,0 @@ | |||||
| /* | |||||
| * 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.classloader; | |||||
| import org.apache.myrmidon.interfaces.ComponentException; | |||||
| /** | |||||
| * An exception thrown by the ClassLoaderManager. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class ClassLoaderException | |||||
| extends ComponentException | |||||
| { | |||||
| /** | |||||
| * Constructs a non-cascaded exception. | |||||
| * | |||||
| * @param message The detail message for this exception. | |||||
| */ | |||||
| public ClassLoaderException( final String message ) | |||||
| { | |||||
| super( message ); | |||||
| } | |||||
| /** | |||||
| * Constructs a cascaded exception. | |||||
| * | |||||
| * @param message The detail message for this exception. | |||||
| * @param throwable the root cause of the exception | |||||
| */ | |||||
| public ClassLoaderException( final String message, final Throwable throwable ) | |||||
| { | |||||
| super( message, throwable ); | |||||
| } | |||||
| } | |||||
| @@ -1,55 +0,0 @@ | |||||
| /* | |||||
| * 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.classloader; | |||||
| import java.io.File; | |||||
| /** | |||||
| * Manages a classloader hierarchy. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface ClassLoaderManager | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = ClassLoaderManager.class.getName(); | |||||
| /** | |||||
| * Returns the ClassLoader for a Jar file. The ClassLoader is created, | |||||
| * if necessary. The ClassLoader's parent will include the common | |||||
| * ClassLoader, along with any extensions required by the Jar file. | |||||
| * It is guaranteed that each extension will appear at most once in the | |||||
| * ClassLoader hierarchy, so that classes from the extension can be | |||||
| * shared across the ClassLoaders returned by this method. | |||||
| * | |||||
| * @param jar the jar file containing the classes to load | |||||
| * @return the classloader | |||||
| * @throws ClassLoaderException on error | |||||
| */ | |||||
| ClassLoader getClassLoader( File jar ) throws ClassLoaderException; | |||||
| /** | |||||
| * Creates a ClassLoader for a set of files. See {@link #getClassLoader} | |||||
| * for details. | |||||
| * | |||||
| * @param jars The Jar/zip files to create the classloader for. Use null | |||||
| * or an empty array to use the common classloader. | |||||
| * @return the created ClassLoader | |||||
| * @throws ClassLoaderException on error | |||||
| */ | |||||
| ClassLoader createClassLoader( File[] jars ) throws ClassLoaderException; | |||||
| /** | |||||
| * Returns the common ClassLoader, which is the parent of all classloaders | |||||
| * built by this ClassLoaderManager. | |||||
| * | |||||
| * @return the common ClassLoader. | |||||
| */ | |||||
| ClassLoader getCommonClassLoader(); | |||||
| } | |||||
| @@ -1,98 +0,0 @@ | |||||
| /* | |||||
| * 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.configurer; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| /** | |||||
| * Class used to configure tasks. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * @ant:role shorthand="configurer" | |||||
| */ | |||||
| public interface Configurer | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = Configurer.class.getName(); | |||||
| /** | |||||
| * Configure an object based on a configuration in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * @param object the object | |||||
| * @param configuration the configuration | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| void configureElement( Object object, Configuration configuration, TaskContext context ) | |||||
| throws ConfigurationException; | |||||
| /** | |||||
| * Configure named attribute of object in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * @param object the object | |||||
| * @param name the attribute name | |||||
| * @param value the attribute value | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| void configureAttribute( Object object, String name, String value, TaskContext context ) | |||||
| throws ConfigurationException; | |||||
| /** | |||||
| * Configure an object based on a configuration in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * The implementation of this method should only use the methods | |||||
| * specified by the supplied class. It is an error for the specified | |||||
| * class not to be a base class or interface compatible with specified | |||||
| * object. | |||||
| * | |||||
| * @param object the object | |||||
| * @param clazz the Class object to use during configuration | |||||
| * @param configuration the configuration | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| void configureElement( Object object, | |||||
| Class clazz, | |||||
| Configuration configuration, | |||||
| TaskContext context ) | |||||
| throws ConfigurationException; | |||||
| /** | |||||
| * Configure named attribute of object in a particular context. | |||||
| * This configuring can be done in different ways for different | |||||
| * configurers. | |||||
| * | |||||
| * The implementation of this method should only use the methods | |||||
| * specified by the supplied class. It is an error for the specified | |||||
| * class not to be a base class or interface compatible with specified | |||||
| * object. | |||||
| * | |||||
| * @param object the object | |||||
| * @param clazz the Class object to use during configuration | |||||
| * @param name the attribute name | |||||
| * @param value the attribute value | |||||
| * @param context the Context | |||||
| * @exception ConfigurationException if an error occurs | |||||
| */ | |||||
| void configureAttribute( Object object, | |||||
| Class clazz, | |||||
| String name, | |||||
| String value, | |||||
| TaskContext context ) | |||||
| throws ConfigurationException; | |||||
| } | |||||
| @@ -1,29 +0,0 @@ | |||||
| /* | |||||
| * 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.converter; | |||||
| /** | |||||
| * Interface for registry for ConverterInfos. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface ConverterRegistry | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = ConverterRegistry.class.getName(); | |||||
| /** | |||||
| * Register a converter | |||||
| * | |||||
| * @param className the className of converter | |||||
| * @param source the source classname | |||||
| * @param destination the destination classname | |||||
| */ | |||||
| void registerConverter( String className, String source, String destination ); | |||||
| } | |||||
| @@ -1,54 +0,0 @@ | |||||
| /* | |||||
| * 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 specialised TypeDefinition which defines a converter. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class ConverterDefinition | |||||
| extends TypeDefinition | |||||
| { | |||||
| private final String m_sourceType; | |||||
| private final String m_destinationType; | |||||
| /** | |||||
| * Creates a converter definition. | |||||
| * @param className the name of the implementing class | |||||
| * @param sourceType the name of the types converted from | |||||
| * @param destinationType the name of the type converted to | |||||
| */ | |||||
| public ConverterDefinition( final String className, | |||||
| final String sourceType, | |||||
| final String destinationType ) | |||||
| { | |||||
| super( className, "converter", className ); | |||||
| m_sourceType = sourceType; | |||||
| m_destinationType = destinationType; | |||||
| } | |||||
| /** | |||||
| * Provides the name of the type which this converter can convert from. | |||||
| * @return the converter's source type. | |||||
| */ | |||||
| public String getSourceType() | |||||
| { | |||||
| return m_sourceType; | |||||
| } | |||||
| /** | |||||
| * Provides the name of the type which this converter can convert to. | |||||
| * @return the converter's destination type. | |||||
| */ | |||||
| public String getDestinationType() | |||||
| { | |||||
| return m_destinationType; | |||||
| } | |||||
| } | |||||
| @@ -1,55 +0,0 @@ | |||||
| /* | |||||
| * 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; | |||||
| import java.io.File; | |||||
| import org.apache.avalon.framework.service.ServiceException; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| /** | |||||
| * This class deploys type libraries into a registry. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface Deployer | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = Deployer.class.getName(); | |||||
| /** | |||||
| * Returns the deployer for the type libraries contained in a ClassLoader, | |||||
| * creating the deployer if necessary. | |||||
| * | |||||
| * @param loader The ClassLoader to get the deployer for. | |||||
| * @return the deployer for this loader. | |||||
| * @exception DeploymentException if an error occurs. | |||||
| */ | |||||
| TypeDeployer createDeployer( ClassLoader loader ) | |||||
| throws DeploymentException; | |||||
| /** | |||||
| * Returns the deployer for a type library, creating the deployer if | |||||
| * necessary. | |||||
| * | |||||
| * @param file the file containing the type library. | |||||
| * @return the deployer for this type library. | |||||
| * @exception DeploymentException if an error occurs. | |||||
| */ | |||||
| TypeDeployer createDeployer( File file ) | |||||
| throws DeploymentException; | |||||
| /** | |||||
| * Creates a deployer which is a child of this deployer. | |||||
| * @param componentManager the ServiceManager for this component. | |||||
| * @return a child deployer. | |||||
| * @throws ServiceException if an error occurs. | |||||
| */ | |||||
| Deployer createChildDeployer( ServiceManager componentManager ) | |||||
| throws ServiceException; | |||||
| } | |||||
| @@ -1,41 +0,0 @@ | |||||
| /* | |||||
| * 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; | |||||
| import org.apache.myrmidon.interfaces.ComponentException; | |||||
| /** | |||||
| * Exception to indicate error deploying. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DeploymentException | |||||
| extends ComponentException | |||||
| { | |||||
| /** | |||||
| * Constructs a non-cascaded exception. | |||||
| * | |||||
| * @param message The detail message for this exception. | |||||
| */ | |||||
| public DeploymentException( final String message ) | |||||
| { | |||||
| super( message ); | |||||
| } | |||||
| /** | |||||
| * Constructs a cascaded exception. | |||||
| * | |||||
| * @param message The detail message for this exception. | |||||
| * @param throwable the root cause of the exception | |||||
| */ | |||||
| public DeploymentException( final String message, final Throwable throwable ) | |||||
| { | |||||
| super( message, throwable ); | |||||
| } | |||||
| } | |||||
| @@ -1,60 +0,0 @@ | |||||
| /* | |||||
| * 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 general-purpose type definition. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class TypeDefinition | |||||
| { | |||||
| private final String m_name; | |||||
| private final String m_role; | |||||
| private final String m_classname; | |||||
| /** | |||||
| * Creates a TypeDefinition | |||||
| * @param name the name of the type | |||||
| * @param roleShorthand the name of the role played by this type | |||||
| * @param className the name of the class implementing this type | |||||
| */ | |||||
| public TypeDefinition( final String name, | |||||
| final String roleShorthand, | |||||
| final String className ) | |||||
| { | |||||
| m_name = name; | |||||
| m_role = roleShorthand; | |||||
| m_classname = className; | |||||
| } | |||||
| /** | |||||
| * @return the type's implementation class name. | |||||
| */ | |||||
| public final String getClassname() | |||||
| { | |||||
| return m_classname; | |||||
| } | |||||
| /** | |||||
| * @return the type's role. | |||||
| */ | |||||
| public final String getRole() | |||||
| { | |||||
| return m_role; | |||||
| } | |||||
| /** | |||||
| * @return the type's name. | |||||
| */ | |||||
| public String getName() | |||||
| { | |||||
| return m_name; | |||||
| } | |||||
| } | |||||
| @@ -1,54 +0,0 @@ | |||||
| /* | |||||
| * 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 <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface TypeDeployer | |||||
| { | |||||
| /** | |||||
| * Deploys everything in the type library. | |||||
| * @throws DeploymentException | |||||
| * If the library cannot be deployed. | |||||
| */ | |||||
| 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 name for the role. | |||||
| * | |||||
| * @param typeName | |||||
| * The type name. | |||||
| * | |||||
| * @throws DeploymentException | |||||
| * If the type cannot be deployed. | |||||
| */ | |||||
| void deployType( String roleShorthand, String typeName ) | |||||
| throws DeploymentException; | |||||
| /** | |||||
| * Deploys a single type from the type library. | |||||
| * | |||||
| * @param typeDef | |||||
| * The type definition. | |||||
| * | |||||
| * @throws DeploymentException | |||||
| * If the type cannot be deployed. | |||||
| */ | |||||
| void deployType( TypeDefinition typeDef ) | |||||
| throws DeploymentException; | |||||
| } | |||||
| @@ -1,65 +0,0 @@ | |||||
| /* | |||||
| * 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.embeddor; | |||||
| import org.apache.avalon.framework.parameters.Parameters; | |||||
| import org.apache.myrmidon.interfaces.model.Project; | |||||
| import org.apache.myrmidon.interfaces.workspace.Workspace; | |||||
| import org.apache.myrmidon.listeners.ProjectListener; | |||||
| import java.util.Map; | |||||
| /** | |||||
| * Interface through which you embed Myrmidon into applications. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface Embeddor | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = Embeddor.class.getName(); | |||||
| /** | |||||
| * Creates a project from a project file. | |||||
| * | |||||
| * @param location The path to the project file. | |||||
| * @param type The project file type. If null the type is inferred from the | |||||
| * project file name. | |||||
| * @param parameters The project builder parameters. | |||||
| * @return the created Project | |||||
| * @throws Exception If an error occurs creating the Project. | |||||
| * | |||||
| * @todo Should location be a URL or will it automatically assume file | |||||
| * unless there is a protocol section like ftp:, file: etc | |||||
| * @todo parameters needs more thought put into it. | |||||
| */ | |||||
| Project createProject( String location, String type, Parameters parameters ) | |||||
| throws Exception; | |||||
| /** | |||||
| * Creates a project listener. | |||||
| * | |||||
| * @param name The shorthand name of the listener. | |||||
| * @return the listener. | |||||
| * @throws Exception If the listener could not be created. | |||||
| */ | |||||
| ProjectListener createListener( String name ) | |||||
| throws Exception; | |||||
| /** | |||||
| * Creates a {@link Workspace} that can be used to execute projects. | |||||
| * | |||||
| * @param properties The properties to define in the workspace. These | |||||
| * are added to the properties in the embeddor's | |||||
| * root execution frame. | |||||
| * @return the Workspace | |||||
| * @throws Exception If the workspace could not be created. | |||||
| */ | |||||
| Workspace createWorkspace( Map properties ) | |||||
| throws Exception; | |||||
| } | |||||
| @@ -1,23 +0,0 @@ | |||||
| /* | |||||
| * 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.executor; | |||||
| /** | |||||
| * This interface is used to supply a root execution frame to a container | |||||
| * that executes tasks. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface ExecutionContainer | |||||
| { | |||||
| /** | |||||
| * Sets the root execution frame for the container. | |||||
| */ | |||||
| void setRootExecutionFrame( ExecutionFrame frame ) throws Exception; | |||||
| } | |||||
| @@ -1,46 +0,0 @@ | |||||
| /* | |||||
| * 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.executor; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| import org.apache.avalon.framework.service.ServiceManager; | |||||
| import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
| /** | |||||
| * An Execution Frame represents the scope in which tasks are executed. | |||||
| * The scope may include an entire workspace, a project, target, or | |||||
| * individual task. | |||||
| * | |||||
| * <p>An Execution Frame bundles together all of the context required to | |||||
| * execute tasks - that is, a set of properties, a set of services, and | |||||
| * a logger. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface ExecutionFrame | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = ExecutionFrame.class.getName(); | |||||
| /** | |||||
| * Returns the set of services to use to create, configure, and execute | |||||
| * tasks. | |||||
| */ | |||||
| ServiceManager getServiceManager(); | |||||
| /** | |||||
| * Returns the logger which is to be supplied to tasks. | |||||
| */ | |||||
| Logger getLogger(); | |||||
| /** | |||||
| * Returns the set of properties to be supplied to tasks. | |||||
| */ | |||||
| PropertyStore getProperties(); | |||||
| } | |||||
| @@ -1,33 +0,0 @@ | |||||
| /* | |||||
| * 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.executor; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| /** | |||||
| * Engine inteface that should be implemented by all tasklet engines. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface Executor | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = Executor.class.getName(); | |||||
| /** | |||||
| * execute a task. | |||||
| * | |||||
| * @param task the configruation data for task | |||||
| * @param frame The frame in which the task is executed. | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| void execute( Configuration task, ExecutionFrame frame ) | |||||
| throws TaskException; | |||||
| } | |||||
| @@ -1,31 +0,0 @@ | |||||
| /* | |||||
| * 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.extensions; | |||||
| import org.apache.avalon.excalibur.extension.Extension; | |||||
| import org.apache.avalon.excalibur.extension.OptionalPackage; | |||||
| /** | |||||
| * Maintains a set of optional packages. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface ExtensionManager | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = ExtensionManager.class.getName(); | |||||
| /** | |||||
| * Locates the optional package which best matches a required extension. | |||||
| * | |||||
| * @param extension the extension to locate an optional package | |||||
| * @return the optional package, or null if not found. | |||||
| */ | |||||
| OptionalPackage getOptionalPackage( Extension extension ); | |||||
| } | |||||
| @@ -1,356 +0,0 @@ | |||||
| /* | |||||
| * 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.model; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| /** | |||||
| * Simple helper class which determines the validity of names used | |||||
| * in ant projects. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultNameValidator | |||||
| implements NameValidator | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultNameValidator.class ); | |||||
| /** | |||||
| * Determines whether the supplied name may include surrounding whitespace. | |||||
| */ | |||||
| private boolean m_allowSurroundingWhitespace; | |||||
| // Settings for initial characters. | |||||
| private boolean m_allowInitialDigit; | |||||
| private String m_additionalInitialCharacters; | |||||
| // Settings for internal characters. | |||||
| private boolean m_allowInternalDigits; | |||||
| private boolean m_allowInternalWhitespace; | |||||
| private String m_additionalInternalCharacters; | |||||
| /** | |||||
| * Construct a default name validator. | |||||
| * Letters, digits and "_" are permitted as initial character. | |||||
| * Letters, digits, whitespace and "_-." are permitted as internal characters. | |||||
| * Surrounding whitespace is not permitted. | |||||
| */ | |||||
| public DefaultNameValidator() | |||||
| { | |||||
| this( false, true, "_", true, true, "_-." ); | |||||
| } | |||||
| /** | |||||
| * Contstruct a NameValidator with the specified rules. | |||||
| * @param allowSurroundingWhitespace | |||||
| * specified if names are trimmed before checking | |||||
| * @param allowInitialDigit | |||||
| * specifies if digits are permitted as intial characters | |||||
| * @param additionalInitialCharacters | |||||
| * extra characters to allow as initial characters. | |||||
| * @param allowInternalDigits | |||||
| * specifies if digits are permitted as internal characters | |||||
| * @param allowInternalWhitespace | |||||
| * specifies if whitespace is permitted internally in names | |||||
| * @param additionalInternalCharacters | |||||
| * extra characters permitted in names | |||||
| */ | |||||
| public DefaultNameValidator( final boolean allowSurroundingWhitespace, | |||||
| final boolean allowInitialDigit, | |||||
| final String additionalInitialCharacters, | |||||
| final boolean allowInternalDigits, | |||||
| final boolean allowInternalWhitespace, | |||||
| final String additionalInternalCharacters ) | |||||
| { | |||||
| setAllowSurroundingWhitespace( allowSurroundingWhitespace ); | |||||
| setAllowInitialDigit( allowInitialDigit ); | |||||
| setAdditionalInitialCharacters( additionalInitialCharacters ); | |||||
| setAllowInternalDigits( allowInternalDigits ); | |||||
| setAllowInternalWhitespace( allowInternalWhitespace ); | |||||
| setAdditionalInternalCharacters( additionalInternalCharacters ); | |||||
| } | |||||
| /** | |||||
| * Creates a valid name based on the supplied string value, removing invalid | |||||
| * characters. If no valid characters are present, an exception is thrown. | |||||
| * @param baseName the name used to construct the valid name | |||||
| * @return a valid name based on the supplied name. | |||||
| * @throws Exception if no valid name could be constructed. | |||||
| */ | |||||
| public String makeValidName( final String baseName ) throws Exception | |||||
| { | |||||
| final StringBuffer buffer = new StringBuffer( baseName ); | |||||
| while( buffer.length() > 0 && !isValidInitialChar( buffer.charAt( 0 ) ) ) | |||||
| { | |||||
| buffer.delete( 0, 1 ); | |||||
| } | |||||
| if( buffer.length() == 0 ) | |||||
| { | |||||
| final String message = REZ.getString( "name.could-not-create.error", baseName ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| for( int i = 1; i < buffer.length(); ) | |||||
| { | |||||
| if( !isValidInternalChar( buffer.charAt( i ) ) ) | |||||
| { | |||||
| buffer.delete( i, i + 1 ); | |||||
| } | |||||
| else | |||||
| { | |||||
| i++; | |||||
| } | |||||
| } | |||||
| return buffer.toString(); | |||||
| } | |||||
| /** | |||||
| * @see NameValidator | |||||
| */ | |||||
| public void validate( final String name ) throws Exception | |||||
| { | |||||
| String testName = name; | |||||
| // If surrounding whitespace is allowed, trim it. Otherwise, check. | |||||
| if( m_allowSurroundingWhitespace ) | |||||
| { | |||||
| testName = testName.trim(); | |||||
| } | |||||
| else | |||||
| { | |||||
| checkSurroundingWhitespace( testName ); | |||||
| } | |||||
| // Zero-length name is invalid. | |||||
| if( testName.length() == 0 ) | |||||
| { | |||||
| final String message = REZ.getString( "name.zero-char-name.error" ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| // Check first character. | |||||
| final char initial = testName.charAt( 0 ); | |||||
| checkInitialCharacter( initial, testName ); | |||||
| // Check the rest of the characters. | |||||
| for( int i = 1; i < testName.length(); i++ ) | |||||
| { | |||||
| final char internal = testName.charAt( i ); | |||||
| checkInternalCharacter( internal, testName ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Checks if the supplied character is permitted as an internal character. | |||||
| * @throws Exception if the character is not permitted | |||||
| */ | |||||
| private void checkInternalCharacter( final char internal, final String name ) | |||||
| throws Exception | |||||
| { | |||||
| if( !isValidInternalChar( internal ) ) | |||||
| { | |||||
| final String message = REZ.getString( "name.invalid-internal-char.error", | |||||
| name, | |||||
| describeValidInternalChars() ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Checks if the supplied character is permitted as an internal character. | |||||
| * @throws Exception if the character is not permitted | |||||
| */ | |||||
| private void checkInitialCharacter( final char initial, final String name ) | |||||
| throws Exception | |||||
| { | |||||
| if( !isValidInitialChar( initial ) ) | |||||
| { | |||||
| final String message = REZ.getString( "name.invalid-initial-char.error", | |||||
| name, | |||||
| describeValidInitialChars() ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Checks the name for surrounding whitespace | |||||
| * @throws Exception if surrounding whitespace is found | |||||
| */ | |||||
| private void checkSurroundingWhitespace( final String testName ) | |||||
| throws Exception | |||||
| { | |||||
| if( testName.length() == 0 ) | |||||
| { | |||||
| return; | |||||
| } | |||||
| if( Character.isWhitespace( testName.charAt( 0 ) ) || | |||||
| Character.isWhitespace( testName.charAt( testName.length() - 1 ) ) ) | |||||
| { | |||||
| final String message = | |||||
| REZ.getString( "name.enclosing-whitespace.error", testName ); | |||||
| throw new Exception( message ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Determines if a character is allowed as the first character in a name. | |||||
| * Valid characters are Letters, Digits, and defined initial characters ("_"). | |||||
| * @param chr the character to be assessed | |||||
| * @return <code>true</code> if the character can be the first character of a name | |||||
| */ | |||||
| protected boolean isValidInitialChar( final char chr ) | |||||
| { | |||||
| if( Character.isLetter( chr ) ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| if( m_allowInitialDigit | |||||
| && Character.isDigit( chr ) ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| if( m_additionalInitialCharacters.indexOf( chr ) != -1 ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| * Determines if a character is allowed as a non-initial character in a name. | |||||
| * Valid characters are Letters, Digits, whitespace, and defined | |||||
| * internal characters ("_-."). | |||||
| * @param chr the character to be assessed | |||||
| * @return <code>true</code> if the character can be included in a name | |||||
| */ | |||||
| protected boolean isValidInternalChar( final char chr ) | |||||
| { | |||||
| if( Character.isLetter( chr ) ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| if( m_allowInternalDigits | |||||
| && Character.isDigit( chr ) ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| if( m_allowInternalWhitespace | |||||
| && Character.isWhitespace( chr ) ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| if( m_additionalInternalCharacters.indexOf( chr ) != -1 ) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| * Builds a message detailing the valid initial characters. | |||||
| */ | |||||
| protected String describeValidInitialChars() | |||||
| { | |||||
| StringBuffer validChars = new StringBuffer( "letters" ); | |||||
| if( m_allowInitialDigit ) | |||||
| { | |||||
| validChars.append( ", digits" ); | |||||
| } | |||||
| validChars.append( ", and \"" ); | |||||
| validChars.append( m_additionalInitialCharacters ); | |||||
| validChars.append( "\"" ); | |||||
| return validChars.toString(); | |||||
| } | |||||
| /** | |||||
| * Builds a message detailing the valid internal characters. | |||||
| */ | |||||
| protected String describeValidInternalChars() | |||||
| { | |||||
| StringBuffer validChars = new StringBuffer( "letters" ); | |||||
| if( m_allowInternalDigits ) | |||||
| { | |||||
| validChars.append( ", digits" ); | |||||
| } | |||||
| if( m_allowInternalWhitespace ) | |||||
| { | |||||
| validChars.append( ", whitespace" ); | |||||
| } | |||||
| validChars.append( ", and \"" ); | |||||
| validChars.append( m_additionalInternalCharacters ); | |||||
| validChars.append( "\"" ); | |||||
| return validChars.toString(); | |||||
| } | |||||
| /** | |||||
| * @param allowSurroundingWhitespace | |||||
| * specified if names are trimmed before checking | |||||
| */ | |||||
| public void setAllowSurroundingWhitespace( boolean allowSurroundingWhitespace ) | |||||
| { | |||||
| m_allowSurroundingWhitespace = allowSurroundingWhitespace; | |||||
| } | |||||
| /** | |||||
| * @param allowInitialDigit | |||||
| * specifies if digits are permitted as intial characters | |||||
| */ | |||||
| public void setAllowInitialDigit( boolean allowInitialDigit ) | |||||
| { | |||||
| m_allowInitialDigit = allowInitialDigit; | |||||
| } | |||||
| /** | |||||
| * @param additionalInitialCharacters | |||||
| * extra characters to allow as initial characters. | |||||
| */ | |||||
| public void setAdditionalInitialCharacters( String additionalInitialCharacters ) | |||||
| { | |||||
| m_additionalInitialCharacters = additionalInitialCharacters; | |||||
| } | |||||
| /** | |||||
| * @param allowInternalDigits | |||||
| * specifies if digits are permitted as internal characters | |||||
| */ | |||||
| public void setAllowInternalDigits( boolean allowInternalDigits ) | |||||
| { | |||||
| m_allowInternalDigits = allowInternalDigits; | |||||
| } | |||||
| /** | |||||
| * @param allowInternalWhitespace | |||||
| * specifies if whitespace is permitted internally in names | |||||
| */ | |||||
| public void setAllowInternalWhitespace( boolean allowInternalWhitespace ) | |||||
| { | |||||
| m_allowInternalWhitespace = allowInternalWhitespace; | |||||
| } | |||||
| /** | |||||
| * @param additionalInternalCharacters | |||||
| * extra characters permitted in names | |||||
| */ | |||||
| public void setAdditionalInternalCharacters( String additionalInternalCharacters ) | |||||
| { | |||||
| m_additionalInternalCharacters = additionalInternalCharacters; | |||||
| } | |||||
| } | |||||
| @@ -1,46 +0,0 @@ | |||||
| /* | |||||
| * 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.model; | |||||
| /** | |||||
| * A dependency for a target. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class Dependency | |||||
| { | |||||
| private final String m_projectName; | |||||
| private final String m_targetName; | |||||
| /** | |||||
| * @param projectName The project containing the depended-on target. | |||||
| * @param targetName The name of the depended-on target. | |||||
| */ | |||||
| public Dependency( final String projectName, final String targetName ) | |||||
| { | |||||
| m_projectName = projectName; | |||||
| m_targetName = targetName; | |||||
| } | |||||
| /** | |||||
| * @return The name of the project containing the depended-on target. | |||||
| */ | |||||
| public String getProjectName() | |||||
| { | |||||
| return m_projectName; | |||||
| } | |||||
| /** | |||||
| * @return The name of the depended-on target. | |||||
| */ | |||||
| public String getTargetName() | |||||
| { | |||||
| return m_targetName; | |||||
| } | |||||
| } | |||||
| @@ -1,26 +0,0 @@ | |||||
| /* | |||||
| * 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.model; | |||||
| /** | |||||
| * Determines the validity of names used in projects. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface NameValidator | |||||
| { | |||||
| /** | |||||
| * Validates the supplied name, failing if it is not. | |||||
| * | |||||
| * @param name The name to be validated. | |||||
| * @throws Exception is the supplied name is not valid. | |||||
| */ | |||||
| void validate( String name ) | |||||
| throws Exception; | |||||
| } | |||||
| @@ -1,100 +0,0 @@ | |||||
| /* | |||||
| * 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.model; | |||||
| import java.io.File; | |||||
| /** | |||||
| * Abstraction used to interact with projects. | |||||
| * Implementations may choose to structure it anyway they choose. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface Project | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = Project.class.getName(); | |||||
| /** Property which holds the name of currently executing project */ | |||||
| String PROJECT = "myrmidon.project.name"; | |||||
| // the name of currently executing project | |||||
| //String PROJECT_FILE = "myrmidon.project.file"; | |||||
| // the name of currently executing target | |||||
| //String TARGET = "myrmidon.target.name"; | |||||
| /** | |||||
| * @return the project name. | |||||
| * | |||||
| * TODO: Determine if projects should carry their own name. Breaks IOC but | |||||
| * Can be useful as project files embed own name (or should that be description). | |||||
| */ | |||||
| String getProjectName(); | |||||
| /** | |||||
| * Get the imports for project. | |||||
| * | |||||
| * @return the imports | |||||
| */ | |||||
| TypeLib[] getTypeLibs(); | |||||
| /** | |||||
| * Get names of projects referenced by this project. | |||||
| * | |||||
| * @return the names | |||||
| */ | |||||
| String[] getProjectNames(); | |||||
| /** | |||||
| * Retrieve project referenced by this project. | |||||
| * | |||||
| * @param name the project name | |||||
| * @return the Project or null if none by that name | |||||
| */ | |||||
| Project getProject( String name ); | |||||
| /** | |||||
| * Get name of default target. | |||||
| * | |||||
| * @return the default target name | |||||
| */ | |||||
| String getDefaultTargetName(); | |||||
| /** | |||||
| * Retrieve implicit target. | |||||
| * The implicit target is top level tasks. | |||||
| * Currently restricted to property tasks. | |||||
| * | |||||
| * @return the Target | |||||
| */ | |||||
| Target getImplicitTarget(); | |||||
| /** | |||||
| * Retrieve a target by name. | |||||
| * | |||||
| * @param name the name of target | |||||
| * @return the Target or null if no target exists with name | |||||
| */ | |||||
| Target getTarget( String name ); | |||||
| /** | |||||
| * Retrieve names of all targets in project. | |||||
| * | |||||
| * @return the iterator of project names | |||||
| */ | |||||
| String[] getTargetNames(); | |||||
| /** | |||||
| * Retrieve base directory of project. | |||||
| * | |||||
| * @return the projects base directory | |||||
| */ | |||||
| File getBaseDirectory(); | |||||
| } | |||||
| @@ -1,6 +0,0 @@ | |||||
| # Name validation | |||||
| name.zero-char-name.error=Name "" is invalid, as it contains no characters. | |||||
| name.enclosing-whitespace.error=Name "{0}" is invalid, as it contains enclosing whitespace. | |||||
| name.invalid-initial-char.error=Name "{0}" is invalid, as it begins with an illegal character. Names can start with {1}. | |||||
| name.invalid-internal-char.error=Name "{0}" is invalid, as it contains an illegal character. Permitted name characters are {1}. | |||||
| name.could-not-create.error=Could not valid name from "{0}". | |||||
| @@ -1,65 +0,0 @@ | |||||
| /* | |||||
| * 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.model; | |||||
| import java.util.ArrayList; | |||||
| import org.apache.avalon.framework.configuration.Configuration; | |||||
| /** | |||||
| * Targets in build file. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class Target | |||||
| { | |||||
| private final ArrayList m_dependencies = new ArrayList(); | |||||
| private final ArrayList m_tasks = new ArrayList(); | |||||
| /** | |||||
| * Constructs a target. | |||||
| * @param tasks The task models for all tasks in this target. | |||||
| * @param dependencies The dependencies for executing this target. | |||||
| */ | |||||
| public Target( final Configuration[] tasks, | |||||
| final Dependency[] dependencies ) | |||||
| { | |||||
| for( int i = 0; i < tasks.length; i++ ) | |||||
| { | |||||
| m_tasks.add( tasks[ i ] ); | |||||
| } | |||||
| if( null != dependencies ) | |||||
| { | |||||
| for( int i = 0; i < dependencies.length; i++ ) | |||||
| { | |||||
| m_dependencies.add( dependencies[ i ] ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get dependencies of target | |||||
| * | |||||
| * @return the dependency list | |||||
| */ | |||||
| public final Dependency[] getDependencies() | |||||
| { | |||||
| return (Dependency[])m_dependencies.toArray( new Dependency[ 0 ] ); | |||||
| } | |||||
| /** | |||||
| * Get tasks in target | |||||
| * | |||||
| * @return the target list | |||||
| */ | |||||
| public final Configuration[] getTasks() | |||||
| { | |||||
| return (Configuration[])m_tasks.toArray( new Configuration[ 0 ] ); | |||||
| } | |||||
| } | |||||
| @@ -1,93 +0,0 @@ | |||||
| /* | |||||
| * 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.model; | |||||
| /** | |||||
| * Imports in a build file. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class TypeLib | |||||
| { | |||||
| //Name of library (this is location independent) | |||||
| private final String m_library; | |||||
| //Do we need this?? | |||||
| //private final String m_namespace; | |||||
| //The role of object to be imported | |||||
| private final String m_role; | |||||
| //The name of type instance | |||||
| private final String m_name; | |||||
| /** | |||||
| * Create a import for a complete library. | |||||
| * @param library The name of the library to import. | |||||
| */ | |||||
| public TypeLib( final String library ) | |||||
| { | |||||
| this( library, null, null ); | |||||
| } | |||||
| /** | |||||
| * Create an import for a single type from a library. | |||||
| * @param library The library containing the type. | |||||
| * @param role The role for the imported type. | |||||
| * @param name The name of the imported type. | |||||
| */ | |||||
| public TypeLib( final String library, final String role, final String name ) | |||||
| { | |||||
| m_library = library; | |||||
| m_role = role; | |||||
| m_name = name; | |||||
| //If only one of name or type is null, throw an exception | |||||
| if( null == m_role || null == m_name ) | |||||
| { | |||||
| if( null != m_role || null != m_name ) | |||||
| { | |||||
| throw new IllegalArgumentException( "Can not have an import that specifies " + | |||||
| "only one of; name or role" ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get role | |||||
| * | |||||
| * @return the role | |||||
| */ | |||||
| public final String getRole() | |||||
| { | |||||
| return m_role; | |||||
| } | |||||
| /** | |||||
| * Get name of imported | |||||
| * | |||||
| * @return the name | |||||
| */ | |||||
| public final String getName() | |||||
| { | |||||
| return m_name; | |||||
| } | |||||
| /** | |||||
| * Get name of library | |||||
| * | |||||
| * @return the library name | |||||
| */ | |||||
| public final String getLibrary() | |||||
| { | |||||
| return m_library; | |||||
| } | |||||
| } | |||||
| @@ -1,119 +0,0 @@ | |||||
| /* | |||||
| * 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.property; | |||||
| import java.util.Map; | |||||
| import java.util.HashMap; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| /** | |||||
| * A simple unscoped, unsynchronized property store which is backed by a Map. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class MapPropertyStore | |||||
| implements PropertyStore | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( MapPropertyStore.class ); | |||||
| private final Map m_properties = new HashMap(); | |||||
| /** | |||||
| * Creates an empty store. | |||||
| */ | |||||
| public MapPropertyStore() | |||||
| { | |||||
| } | |||||
| /** | |||||
| * Creates a store containing the given properties. | |||||
| */ | |||||
| public MapPropertyStore( final Map properties ) | |||||
| { | |||||
| m_properties.putAll( properties ); | |||||
| } | |||||
| /** | |||||
| * Return <code>true</code> if the specified property is set. | |||||
| * | |||||
| * @param name the name of property | |||||
| */ | |||||
| public boolean isPropertySet( final String name ) | |||||
| { | |||||
| return m_properties.containsKey( name ); | |||||
| } | |||||
| /** | |||||
| * Retrieve the value of specified property. | |||||
| * | |||||
| * @param name the name of the property | |||||
| * @return the value of the property. Never returns null. | |||||
| * @throws TaskException if there is no such property, or on error | |||||
| * retrieving property, such as an invalid property name. | |||||
| */ | |||||
| public Object getProperty( final String name ) | |||||
| throws TaskException | |||||
| { | |||||
| final Object value = m_properties.get( name ); | |||||
| if( value == null ) | |||||
| { | |||||
| final String message = REZ.getString( "unknown-property.error", name ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| return value; | |||||
| } | |||||
| /** | |||||
| * Retrieve a copy of all the properties that are "in-scope" | |||||
| * for store. | |||||
| * | |||||
| * @return a copy of all the properties that are "in-scope" | |||||
| * for store. | |||||
| * @throws TaskException if theres an error retrieving propertys | |||||
| */ | |||||
| public Map getProperties() | |||||
| throws TaskException | |||||
| { | |||||
| return new HashMap( m_properties ); | |||||
| } | |||||
| /** | |||||
| * Set the property with specified name to specified value. | |||||
| * The specific implementation will apply various rules | |||||
| * before setting the property. | |||||
| * | |||||
| * @param name the name of property | |||||
| * @param value the value of property | |||||
| * @throws TaskException if property can not be set | |||||
| */ | |||||
| public void setProperty( String name, Object value ) | |||||
| throws TaskException | |||||
| { | |||||
| m_properties.put( name, value ); | |||||
| } | |||||
| /** | |||||
| * Return a child PropertyStore with specified name. | |||||
| * This is to allow support for scoped stores. However a | |||||
| * store may choose to be unscoped and just return a | |||||
| * reference to itself. | |||||
| * | |||||
| * @param name the name of child store | |||||
| * @return the child store | |||||
| * @throws TaskException if theres an error creating child store | |||||
| */ | |||||
| public PropertyStore createChildStore( String name ) | |||||
| throws TaskException | |||||
| { | |||||
| return this; | |||||
| } | |||||
| } | |||||
| @@ -1,41 +0,0 @@ | |||||
| /* | |||||
| * 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.property; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| /** | |||||
| * | |||||
| * Provides a service for the resolution of property identifiers within | |||||
| * String content. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | |||||
| * @ant:role shorthand="property-resolver" | |||||
| */ | |||||
| public interface PropertyResolver | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = PropertyResolver.class.getName(); | |||||
| /** | |||||
| * Resolve a string property. This evaluates all property | |||||
| * substitutions based on specified contex. | |||||
| * Rules used for property resolution are implementation dependent. | |||||
| * | |||||
| * @param value the value to resolve, which may contain property identifiers | |||||
| * @param context the set of properties to resolve against. | |||||
| * @return the resolved content | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| Object resolveProperties( final String value, | |||||
| final TaskContext context ) | |||||
| throws TaskException; | |||||
| } | |||||
| @@ -1,86 +0,0 @@ | |||||
| /* | |||||
| * 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.property; | |||||
| import java.util.Map; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| /** | |||||
| * This component stores and manages properties. It is also | |||||
| * responsible for instituting the various policies regarding | |||||
| * propertys. ie It will enforce rules regarding | |||||
| * | |||||
| * <ul> | |||||
| * <li>Valid property names?</li> | |||||
| * <li>Are propertys mutable?</li> | |||||
| * <li>Are propertys scoped?</li> | |||||
| * <li>Is mapping between name and value correct?</li> | |||||
| * </ul> | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface PropertyStore | |||||
| { | |||||
| /** Role name for this interface. */ | |||||
| String ROLE = PropertyStore.class.getName(); | |||||
| /** | |||||
| * Set the property with specified name to specified value. | |||||
| * The specific implementation will apply various rules | |||||
| * before setting the property. | |||||
| * | |||||
| * @param name the name of property | |||||
| * @param value the value of property | |||||
| * @throws TaskException if property can not be set | |||||
| */ | |||||
| void setProperty( String name, Object value ) | |||||
| throws TaskException; | |||||
| /** | |||||
| * Return <code>true</code> if the specified property is set. | |||||
| * | |||||
| * @param name the name of property | |||||
| */ | |||||
| boolean isPropertySet( String name ); | |||||
| /** | |||||
| * Retrieve the value of specified property. | |||||
| * | |||||
| * @param name the name of the property | |||||
| * @return the value of the property. Never returns null. | |||||
| * @throws TaskException if there is no such property, or on error | |||||
| * retrieving property, such as an invalid property name. | |||||
| */ | |||||
| Object getProperty( String name ) | |||||
| throws TaskException; | |||||
| /** | |||||
| * Retrieve a copy of all the properties that are "in-scope" | |||||
| * for store. | |||||
| * | |||||
| * @return a copy of all the properties that are "in-scope" | |||||
| * for store. | |||||
| * @throws TaskException if theres an error retrieving propertys | |||||
| */ | |||||
| Map getProperties() | |||||
| throws TaskException; | |||||
| /** | |||||
| * Return a child PropertyStore with specified name. | |||||
| * This is to allow support for scoped stores. However a | |||||
| * store may choose to be unscoped and just return a | |||||
| * reference to itself. | |||||
| * | |||||
| * @param name the name of child store | |||||
| * @return the child store | |||||
| * @throws TaskException if theres an error creating child store | |||||
| */ | |||||
| PropertyStore createChildStore( String name ) | |||||
| throws TaskException; | |||||
| } | |||||