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"> | |||
| <pathelement location="build/classes"/> | |||
| <fileset dir="lib"> | |||
| <include name="*.jar"/> | |||
| <include name="**/*.jar"/> | |||
| </fileset> | |||
| </path> | |||
| @@ -251,9 +251,7 @@ Legal: | |||
| <src path="${build.src}" /> | |||
| --> | |||
| <patternset refid="myrmidon-launcher.include"/> | |||
| <patternset refid="myrmidon-framework.include"/> | |||
| <patternset refid="myrmidon-container.include"/> | |||
| <patternset refid="ant1.todo.include"/> | |||
| <patternset refid="selftest.include"/> | |||
| <patternset refid="selftest-extension1.include"/> | |||
| @@ -269,22 +267,12 @@ Legal: | |||
| </target> | |||
| <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"> | |||
| <include name="org/apache/myrmidon/interfaces/**" /> | |||
| <include name="org/apache/myrmidon/framework/**" /> | |||
| </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="taskdefs.package" value="${ant.package}/taskdefs"/> | |||
| <property name="antlib.package" value="org/apache/antlib"/> | |||
| @@ -390,14 +378,6 @@ Legal: | |||
| </fileset> | |||
| </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" | |||
| destdir="${gen.dir}" | |||
| classpathref="project.class.path"> | |||
| @@ -422,20 +402,6 @@ Legal: | |||
| <mkdir dir="${build.lib}"/> | |||
| <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" | |||
| basedir="${build.classes}" | |||
| 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; | |||
| } | |||