Note this wont run until we break out container-api.jar and place in lib/ so that the runtime/ant1compat classes will work at runtime. At the moment they will compile ma no run. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272374 13f79535-47bb-0310-9956-ffa450edef68master
@@ -14,7 +14,7 @@ | |||||
<path id="project.class.path"> | <path id="project.class.path"> | ||||
<pathelement location="build/classes"/> | <pathelement location="build/classes"/> | ||||
<fileset dir="lib"> | <fileset dir="lib"> | ||||
<include name="*.jar"/> | |||||
<include name="**/*.jar"/> | |||||
</fileset> | </fileset> | ||||
</path> | </path> | ||||
@@ -251,9 +251,7 @@ Legal: | |||||
<src path="${build.src}" /> | <src path="${build.src}" /> | ||||
--> | --> | ||||
<patternset refid="myrmidon-launcher.include"/> | |||||
<patternset refid="myrmidon-framework.include"/> | <patternset refid="myrmidon-framework.include"/> | ||||
<patternset refid="myrmidon-container.include"/> | |||||
<patternset refid="ant1.todo.include"/> | <patternset refid="ant1.todo.include"/> | ||||
<patternset refid="selftest.include"/> | <patternset refid="selftest.include"/> | ||||
<patternset refid="selftest-extension1.include"/> | <patternset refid="selftest-extension1.include"/> | ||||
@@ -269,22 +267,12 @@ Legal: | |||||
</target> | </target> | ||||
<target name="setup-patterns" depends="check_for_optional_packages"> | <target name="setup-patterns" depends="check_for_optional_packages"> | ||||
<patternset id="myrmidon-launcher.include"> | |||||
<include name="org/apache/myrmidon/launcher/**" /> | |||||
</patternset> | |||||
<patternset id="myrmidon-framework.include"> | <patternset id="myrmidon-framework.include"> | ||||
<include name="org/apache/myrmidon/interfaces/**" /> | <include name="org/apache/myrmidon/interfaces/**" /> | ||||
<include name="org/apache/myrmidon/framework/**" /> | <include name="org/apache/myrmidon/framework/**" /> | ||||
</patternset> | </patternset> | ||||
<patternset id="myrmidon-container.include"> | |||||
<include name="org/apache/myrmidon/components/**" /> | |||||
<include name="org/apache/myrmidon/frontends/**" /> | |||||
<include name="org/apache/myrmidon/*" /> | |||||
<exclude name="**/TransformingProjectBuilder.java" unless="trax.present"/> | |||||
</patternset> | |||||
<property name="ant.package" value="org/apache/tools/todo"/> | <property name="ant.package" value="org/apache/tools/todo"/> | ||||
<property name="taskdefs.package" value="${ant.package}/taskdefs"/> | <property name="taskdefs.package" value="${ant.package}/taskdefs"/> | ||||
<property name="antlib.package" value="org/apache/antlib"/> | <property name="antlib.package" value="org/apache/antlib"/> | ||||
@@ -390,14 +378,6 @@ Legal: | |||||
</fileset> | </fileset> | ||||
</antlib-descriptor> | </antlib-descriptor> | ||||
<antlib-descriptor libName="container" | |||||
destdir="${gen.dir}" | |||||
classpathref="project.class.path"> | |||||
<fileset dir="${java.dir}"> | |||||
<patternset refid="myrmidon-container.include"/> | |||||
</fileset> | |||||
</antlib-descriptor> | |||||
<antlib-descriptor libName="selftest" | <antlib-descriptor libName="selftest" | ||||
destdir="${gen.dir}" | destdir="${gen.dir}" | ||||
classpathref="project.class.path"> | classpathref="project.class.path"> | ||||
@@ -422,20 +402,6 @@ Legal: | |||||
<mkdir dir="${build.lib}"/> | <mkdir dir="${build.lib}"/> | ||||
<mkdir dir="${build.ext}"/> | <mkdir dir="${build.ext}"/> | ||||
<jar jarfile="${build.bin}/myrmidon-launcher.jar" | |||||
basedir="${build.classes}" | |||||
manifest="${manifest.dir}/myrmidon-launcher.mf"> | |||||
<patternset refid="myrmidon-launcher.include"/> | |||||
</jar> | |||||
<antlib-jar jarfile="${build.bin}/lib/myrmidon-container.jar" | |||||
basedir="${build.classes}" | |||||
manifest="${manifest.dir}/myrmidon-container.mf" | |||||
rolesDescriptor="${gen.dir}/container-ant-roles.xml" | |||||
descriptor="${gen.dir}/container-ant-descriptor.xml" > | |||||
<patternset refid="myrmidon-container.include"/> | |||||
</antlib-jar> | |||||
<antlib-jar jarfile="${build.lib}/myrmidon-framework.jar" | <antlib-jar jarfile="${build.lib}/myrmidon-framework.jar" | ||||
basedir="${build.classes}" | basedir="${build.classes}" | ||||
manifest="${manifest.dir}/myrmidon-api.mf" | manifest="${manifest.dir}/myrmidon-api.mf" | ||||
@@ -1,179 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.aspect; | |||||
import java.util.HashMap; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.activity.Initializable; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
import org.apache.avalon.framework.parameters.Parameters; | |||||
import org.apache.myrmidon.api.Task; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.aspects.AspectHandler; | |||||
import org.apache.myrmidon.aspects.NoopAspectHandler; | |||||
import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||||
/** | |||||
* Manage and propogate Aspects. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultAspectManager | |||||
implements AspectManager, Initializable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultAspectManager.class ); | |||||
private HashMap m_aspectMap = new HashMap(); | |||||
private AspectHandler[] m_aspects = new AspectHandler[ 0 ]; | |||||
private String[] m_names = new String[ 0 ]; | |||||
public void initialize() | |||||
throws Exception | |||||
{ | |||||
///UGLY HACK!!!! | |||||
addAspectHandler( "ant", new NoopAspectHandler() ); | |||||
addAspectHandler( "doc", new NoopAspectHandler() ); | |||||
} | |||||
public synchronized void addAspectHandler( final String name, final AspectHandler handler ) | |||||
throws TaskException | |||||
{ | |||||
m_aspectMap.put( name, handler ); | |||||
rebuildArrays(); | |||||
} | |||||
public synchronized void removeAspectHandler( final String name ) | |||||
throws TaskException | |||||
{ | |||||
final AspectHandler entry = (AspectHandler)m_aspectMap.remove( name ); | |||||
if( null == entry ) | |||||
{ | |||||
final String message = REZ.getString( "no.aspect", name ); | |||||
throw new TaskException( message ); | |||||
} | |||||
rebuildArrays(); | |||||
} | |||||
private void rebuildArrays() | |||||
{ | |||||
m_aspects = (AspectHandler[])m_aspectMap.values().toArray( m_aspects ); | |||||
m_names = (String[])m_aspectMap.keySet().toArray( m_names ); | |||||
} | |||||
public String[] getNames() | |||||
{ | |||||
return m_names; | |||||
} | |||||
public void dispatchAspectSettings( final String name, | |||||
final Parameters parameters, | |||||
final Configuration[] elements ) | |||||
throws TaskException | |||||
{ | |||||
final AspectHandler handler = (AspectHandler)m_aspectMap.get( name ); | |||||
if( null == handler ) | |||||
{ | |||||
final String message = REZ.getString( "no.aspect", name ); | |||||
throw new TaskException( message ); | |||||
} | |||||
handler.aspectSettings( parameters, elements ); | |||||
} | |||||
public Configuration preCreate( final Configuration configuration ) | |||||
throws TaskException | |||||
{ | |||||
Configuration model = configuration; | |||||
final AspectHandler[] aspects = m_aspects; | |||||
for( int i = 0; i < aspects.length; i++ ) | |||||
{ | |||||
model = aspects[ i ].preCreate( model ); | |||||
} | |||||
return model; | |||||
} | |||||
public void aspectSettings( final Parameters parameters, final Configuration[] elements ) | |||||
throws TaskException | |||||
{ | |||||
final String message = REZ.getString( "no.settings" ); | |||||
throw new UnsupportedOperationException( message ); | |||||
} | |||||
public void postCreate( final Task task ) | |||||
throws TaskException | |||||
{ | |||||
final AspectHandler[] aspects = m_aspects; | |||||
for( int i = 0; i < aspects.length; i++ ) | |||||
{ | |||||
aspects[ i ].postCreate( task ); | |||||
} | |||||
} | |||||
public void preLogEnabled( final Logger logger ) | |||||
throws TaskException | |||||
{ | |||||
final AspectHandler[] aspects = m_aspects; | |||||
for( int i = 0; i < aspects.length; i++ ) | |||||
{ | |||||
aspects[ i ].preLogEnabled( logger ); | |||||
} | |||||
} | |||||
public void preConfigure( final Configuration taskModel ) | |||||
throws TaskException | |||||
{ | |||||
final AspectHandler[] aspects = m_aspects; | |||||
for( int i = 0; i < aspects.length; i++ ) | |||||
{ | |||||
aspects[ i ].preConfigure( taskModel ); | |||||
} | |||||
} | |||||
public void preExecute() | |||||
throws TaskException | |||||
{ | |||||
final AspectHandler[] aspects = m_aspects; | |||||
for( int i = 0; i < aspects.length; i++ ) | |||||
{ | |||||
aspects[ i ].preExecute(); | |||||
} | |||||
} | |||||
public void preDestroy() | |||||
throws TaskException | |||||
{ | |||||
final AspectHandler[] aspects = m_aspects; | |||||
for( int i = 0; i < aspects.length; i++ ) | |||||
{ | |||||
aspects[ i ].preDestroy(); | |||||
} | |||||
} | |||||
public boolean error( final TaskException te ) | |||||
throws TaskException | |||||
{ | |||||
final AspectHandler[] aspects = m_aspects; | |||||
for( int i = 0; i < aspects.length; i++ ) | |||||
{ | |||||
final boolean isError = aspects[ i ].error( te ); | |||||
if( isError ) | |||||
{ | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
} |
@@ -1,2 +0,0 @@ | |||||
no.aspect=No such aspect with name {0}. | |||||
no.settings=Can not provide Settings to AspectManager. |
@@ -1,227 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.builder; | |||||
import java.io.InputStream; | |||||
import java.net.URL; | |||||
import java.util.Properties; | |||||
import javax.xml.parsers.SAXParser; | |||||
import javax.xml.parsers.SAXParserFactory; | |||||
import javax.xml.transform.Transformer; | |||||
import javax.xml.transform.TransformerFactory; | |||||
import javax.xml.transform.sax.SAXResult; | |||||
import javax.xml.transform.stream.StreamSource; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||||
import org.apache.avalon.framework.parameters.Parameterizable; | |||||
import org.apache.avalon.framework.parameters.Parameters; | |||||
import org.xml.sax.SAXException; | |||||
import org.xml.sax.XMLReader; | |||||
/** | |||||
* Default implementation to construct project from a build file. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
* @ant.type type="project-builder" name="ati" | |||||
*/ | |||||
public class ATIProjectBuilder | |||||
extends DefaultProjectBuilder | |||||
implements Parameterizable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( ATIProjectBuilder.class ); | |||||
private Parameters m_parameters; | |||||
public void parameterize( final Parameters parameters ) | |||||
{ | |||||
m_parameters = parameters; | |||||
} | |||||
protected void process( final URL sourceID, | |||||
final SAXConfigurationHandler handler ) | |||||
throws Exception | |||||
{ | |||||
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||||
final SAXParser saxParser = saxParserFactory.newSAXParser(); | |||||
final XMLReader reader = saxParser.getXMLReader(); | |||||
reader.setFeature( "http://xml.org/sax/features/validation", false ); | |||||
reader.setErrorHandler( handler ); | |||||
final ReactorPIHandler reactorHandler = new ReactorPIHandler(); | |||||
reader.setContentHandler( reactorHandler ); | |||||
try | |||||
{ | |||||
reader.parse( sourceID.toString() ); | |||||
} | |||||
catch( final StopParsingException spe ) | |||||
{ | |||||
//Ignore me | |||||
} | |||||
Transformer transformer = null; | |||||
final int size = reactorHandler.getPICount(); | |||||
for( int i = 0; i < size; i++ ) | |||||
{ | |||||
final String target = reactorHandler.getTarget( i ); | |||||
final String data = reactorHandler.getData( i ); | |||||
if( target.equals( "xsl-param" ) ) | |||||
{ | |||||
handleParameter( data ); | |||||
} | |||||
else if( target.equals( "xsl-params" ) ) | |||||
{ | |||||
handleParameters( data, sourceID ); | |||||
} | |||||
else if( target.equals( "xsl-stylesheet" ) ) | |||||
{ | |||||
if( null != transformer ) | |||||
{ | |||||
final String message = REZ.getString( "ati.two.stylesheet.pis" ); | |||||
throw new SAXException( message ); | |||||
} | |||||
final TransformerFactory factory = TransformerFactory.newInstance(); | |||||
final String stylesheet = getStylesheet( data, sourceID ); | |||||
transformer = factory.newTransformer( new StreamSource( stylesheet ) ); | |||||
} | |||||
} | |||||
if( null == transformer ) | |||||
{ | |||||
reader.setContentHandler( handler ); | |||||
reader.parse( sourceID.toString() ); | |||||
} | |||||
else | |||||
{ | |||||
final String[] names = m_parameters.getNames(); | |||||
for( int i = 0; i < names.length; i++ ) | |||||
{ | |||||
final String name = names[ i ]; | |||||
final String value = m_parameters.getParameter( name ); | |||||
transformer.setParameter( name, value ); | |||||
} | |||||
final SAXResult result = new SAXResult( handler ); | |||||
transformer.transform( new StreamSource( sourceID.toString() ), result ); | |||||
//transformer.transform( new StreamSource( sourceID.toString() ), | |||||
//new StreamResult( System.out ) ); | |||||
} | |||||
} | |||||
private void handleParameter( final String data ) | |||||
throws SAXException | |||||
{ | |||||
int index = data.indexOf( '\"' ); | |||||
if( -1 == index ) | |||||
{ | |||||
final String message = REZ.getString( "ati.param.error" ); | |||||
throw new SAXException( message ); | |||||
} | |||||
index = data.indexOf( '\"', index + 1 ); | |||||
if( -1 == index ) | |||||
{ | |||||
final String message = REZ.getString( "ati.param.error" ); | |||||
throw new SAXException( message ); | |||||
} | |||||
//split between two "attributes" occurs on index | |||||
final String[] name = parseAttribute( data.substring( 0, index + 1 ) ); | |||||
final String[] value = parseAttribute( data.substring( index + 1 ).trim() ); | |||||
if( !name[ 0 ].equals( "name" ) || !value[ 0 ].equals( "value" ) ) | |||||
{ | |||||
final String message = REZ.getString( "ati.param.error" ); | |||||
throw new SAXException( message ); | |||||
} | |||||
m_parameters.setParameter( name[ 1 ], value[ 1 ] ); | |||||
} | |||||
private void handleParameters( final String data, final URL baseSource ) | |||||
throws SAXException | |||||
{ | |||||
final String[] params = parseAttribute( data ); | |||||
if( !params[ 0 ].equals( "location" ) ) | |||||
{ | |||||
final String message = REZ.getString( "ati.params.error" ); | |||||
throw new SAXException( message ); | |||||
} | |||||
try | |||||
{ | |||||
final Properties properties = new Properties(); | |||||
final URL url = new URL( baseSource, params[ 1 ] ); | |||||
final InputStream input = url.openStream(); | |||||
properties.load( input ); | |||||
final Parameters parameters = Parameters.fromProperties( properties ); | |||||
m_parameters.merge( parameters ); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "ati.loading-params.error", params[ 1 ], e ); | |||||
throw new SAXException( message ); | |||||
} | |||||
} | |||||
private String getStylesheet( final String data, final URL baseSource ) | |||||
throws SAXException | |||||
{ | |||||
final String[] stylesheet = parseAttribute( data ); | |||||
if( !stylesheet[ 0 ].equals( "href" ) ) | |||||
{ | |||||
final String message = REZ.getString( "ati.style.error" ); | |||||
throw new SAXException( message ); | |||||
} | |||||
try | |||||
{ | |||||
return new URL( baseSource, stylesheet[ 1 ] ).toString(); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ati.loading-style.error", stylesheet[ 1 ], e ); | |||||
throw new SAXException( message ); | |||||
} | |||||
} | |||||
private String[] parseAttribute( final String data ) | |||||
throws SAXException | |||||
{ | |||||
//name="value" | |||||
int index = data.indexOf( '=' ); | |||||
if( -1 == index ) | |||||
{ | |||||
final String message = REZ.getString( "ati.attribue-expected.error", data ); | |||||
throw new SAXException( message ); | |||||
} | |||||
final int size = data.length(); | |||||
if( '\"' != data.charAt( index + 1 ) || | |||||
'\"' != data.charAt( size - 1 ) || | |||||
size - 1 == index ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ati.attribue-unquoted.error", data.substring( 0, index ) ); | |||||
throw new SAXException( message ); | |||||
} | |||||
final String[] result = new String[ 2 ]; | |||||
result[ 0 ] = data.substring( 0, index ); | |||||
result[ 1 ] = data.substring( index + 2, size - 1 ); | |||||
return result; | |||||
} | |||||
} |
@@ -1,247 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.builder; | |||||
import java.util.HashSet; | |||||
import java.util.Set; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.configuration.DefaultConfiguration; | |||||
import org.apache.myrmidon.interfaces.builder.ProjectException; | |||||
/** | |||||
* A simple ProjectBuilder, which programmatically converts an Ant1 Project | |||||
* configuration into a Myrmidon one. | |||||
* | |||||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
* @version $Revision$ $Date$ | |||||
* | |||||
* @ant.type type="project-builder" name="xml" | |||||
* @ant.type type="project-builder" name="ant" | |||||
* @ant.type type="project-builder" name="default" | |||||
*/ | |||||
public class ConvertingProjectBuilder | |||||
extends DefaultProjectBuilder | |||||
{ | |||||
private static final String VERSION_ATTRIBUTE = "version"; | |||||
/** | |||||
* Builds a Configuration from an Ant1 project file, converting it | |||||
* into a valid Myrmidon Project. | |||||
* @param systemID the xml Systemid of the project file. | |||||
* @return the configured project | |||||
* @throws ProjectException if an error occurs parsing the project file | |||||
*/ | |||||
protected Configuration parseProject( final String systemID ) | |||||
throws ProjectException | |||||
{ | |||||
final Configuration originalConfig = super.parseProject( systemID ); | |||||
// Check the version, if it's present, just use this config. | |||||
// TODO: check for version < 2.0 | |||||
if( originalConfig.getAttribute( VERSION_ATTRIBUTE, null ) != null ) | |||||
{ | |||||
return originalConfig; | |||||
} | |||||
// Convert the config by prepending "ant1." on tasks, | |||||
// and using <if> tasks instead of target 'if=' and 'unless=' | |||||
final DefaultConfiguration newConfig = copyConfiguration( originalConfig ); | |||||
// Put a new version attribute. | |||||
newConfig.setAttribute( VERSION_ATTRIBUTE, "2.0" ); | |||||
// Copy the remaining attributes. | |||||
final Set omitAttributes = new HashSet(); | |||||
omitAttributes.add( VERSION_ATTRIBUTE ); | |||||
copyAttributes( originalConfig, newConfig, omitAttributes ); | |||||
// Now copy/convert the children | |||||
final Configuration[] children = originalConfig.getChildren(); | |||||
for( int i = 0; i < children.length; i++ ) | |||||
{ | |||||
final Configuration child = children[ i ]; | |||||
if( child.getName().equals( "target" ) ) | |||||
{ | |||||
newConfig.addChild( convertTarget( child ) ); | |||||
} | |||||
else | |||||
{ | |||||
newConfig.addChild( convertTask( child ) ); | |||||
} | |||||
} | |||||
return newConfig; | |||||
} | |||||
/** | |||||
* Converts Configuration for an Ant1 Target into a Myrmidon version. | |||||
* @param originalTarget The Ant1 Target | |||||
* @return the converted target | |||||
*/ | |||||
private Configuration convertTarget( final Configuration originalTarget ) | |||||
{ | |||||
final DefaultConfiguration newTarget = copyConfiguration( originalTarget ); | |||||
// Copy all attributes except 'if' and 'unless' | |||||
final Set omitAttributes = new HashSet(); | |||||
omitAttributes.add( "if" ); | |||||
omitAttributes.add( "unless" ); | |||||
copyAttributes( originalTarget, newTarget, omitAttributes ); | |||||
DefaultConfiguration containerElement = newTarget; | |||||
// For 'if="prop-name"', replace with <if> task. | |||||
final String ifAttrib = originalTarget.getAttribute( "if", null ); | |||||
if ( ifAttrib != null ) | |||||
{ | |||||
final DefaultConfiguration ifElement = | |||||
buildIfElement( ifAttrib, false, originalTarget.getLocation() ); | |||||
containerElement.addChild( ifElement ); | |||||
// Treat the ifElement as the enclosing target. | |||||
containerElement = ifElement; | |||||
} | |||||
// For 'unless="prop-name"', replace with <if> task (negated). | |||||
final String unlessAttrib = originalTarget.getAttribute( "unless", null ); | |||||
if ( unlessAttrib != null ) | |||||
{ | |||||
final DefaultConfiguration unlessElement = | |||||
buildIfElement( unlessAttrib, true, originalTarget.getLocation() ); | |||||
containerElement.addChild( unlessElement ); | |||||
// Treat the unlessElement as the enclosing target. | |||||
containerElement = unlessElement; | |||||
} | |||||
// Now copy in converted tasks. | |||||
final Configuration[] tasks = originalTarget.getChildren(); | |||||
for( int i = 0; i < tasks.length; i++ ) | |||||
{ | |||||
containerElement.addChild( convertTask( tasks[ i ] ) ); | |||||
} | |||||
return newTarget; | |||||
} | |||||
/** | |||||
* Builds configuration for an <if> task, to replace a "if" or "unless" | |||||
* attribute on a Ant1 target. | |||||
* @param ifProperty the name of the property from the Ant1 attribute. | |||||
* @param unless if the attribute is actually an "unless" attribute. | |||||
* @param location the configuration location to use | |||||
* @return The configuration for an <if> task | |||||
*/ | |||||
private DefaultConfiguration buildIfElement( final String ifProperty, | |||||
final boolean unless, | |||||
final String location ) | |||||
{ | |||||
// <if> | |||||
// <condition> | |||||
// <is-set property="prop-name"/> | |||||
// </condition> | |||||
// .. tasks | |||||
// </if> | |||||
final DefaultConfiguration isSetElement = | |||||
new DefaultConfiguration( "is-set", location ); | |||||
isSetElement.setAttribute( "property", ifProperty ); | |||||
final DefaultConfiguration conditionElement = | |||||
new DefaultConfiguration( "condition", location ); | |||||
if ( unless ) | |||||
{ | |||||
// Surround <is-set> with <not> | |||||
final DefaultConfiguration notElement = | |||||
new DefaultConfiguration( "not", location ); | |||||
notElement.addChild( isSetElement ); | |||||
conditionElement.addChild( notElement ); | |||||
} | |||||
else | |||||
{ | |||||
conditionElement.addChild( isSetElement ); | |||||
} | |||||
final DefaultConfiguration ifElement = | |||||
new DefaultConfiguration( "if", location ); | |||||
ifElement.addChild( conditionElement ); | |||||
return ifElement; | |||||
} | |||||
/** | |||||
* Converts Configuration for an Ant1 Task into a Myrmidon version. | |||||
* @param originalTask The Ant1 Task | |||||
* @return the converted task | |||||
*/ | |||||
private Configuration convertTask( final Configuration originalTask ) | |||||
{ | |||||
// Create a new configuration with the "ant1." prefix. | |||||
final String newTaskName = "ant1." + originalTask.getName(); | |||||
final DefaultConfiguration newTask = | |||||
new DefaultConfiguration( newTaskName, originalTask.getLocation() ); | |||||
// Copy all attributes and elements of the task. | |||||
copyAttributes( originalTask, newTask, new HashSet() ); | |||||
copyChildren( originalTask, newTask ); | |||||
return newTask; | |||||
} | |||||
/** | |||||
* Copies all child elements from one configuration to another | |||||
* @param from Configuration to copy from | |||||
* @param to Configuration to copy to | |||||
*/ | |||||
private void copyChildren( final Configuration from, | |||||
final DefaultConfiguration to ) | |||||
{ | |||||
final Configuration[] children = from.getChildren(); | |||||
for( int i = 0; i < children.length; i++ ) | |||||
{ | |||||
to.addChild( children[ i ] ); | |||||
} | |||||
} | |||||
/** | |||||
* Copies all attributes from one configuration to another, excluding | |||||
* specified attribute names. | |||||
* @param from Configuration to copy from | |||||
* @param to Configuration to copy to | |||||
* @param omitAttributes a Set of attribute names to exclude | |||||
*/ | |||||
private void copyAttributes( final Configuration from, | |||||
final DefaultConfiguration to, | |||||
final Set omitAttributes ) | |||||
{ | |||||
// Copy other attributes | |||||
final String[] attribs = from.getAttributeNames(); | |||||
for( int i = 0; i < attribs.length; i++ ) | |||||
{ | |||||
final String name = attribs[ i ]; | |||||
if( omitAttributes.contains( name ) ) | |||||
{ | |||||
continue; | |||||
} | |||||
final String value = from.getAttribute( name, "" ); | |||||
to.setAttribute( name, value ); | |||||
} | |||||
} | |||||
/** | |||||
* Creates a DefaultConfiguration with the same name and location as | |||||
* the one supplied. | |||||
* @param originalConfig the COnfiguration to copy. | |||||
* @return the new Configuration | |||||
*/ | |||||
private DefaultConfiguration copyConfiguration( final Configuration originalConfig ) | |||||
{ | |||||
return new DefaultConfiguration( originalConfig.getName(), | |||||
originalConfig.getLocation() ); | |||||
} | |||||
} |
@@ -1,229 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.builder; | |||||
import java.io.File; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.myrmidon.interfaces.model.Project; | |||||
import org.apache.myrmidon.interfaces.model.Target; | |||||
import org.apache.myrmidon.interfaces.model.TypeLib; | |||||
/** | |||||
* Default project implementation. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultProject | |||||
implements Project | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultProject.class ); | |||||
///The imports | |||||
private final ArrayList m_imports = new ArrayList(); | |||||
///The projects refferred to by this project | |||||
private final HashMap m_projects = new HashMap(); | |||||
///The targets contained by this project | |||||
private final HashMap m_targets = new HashMap(); | |||||
///The implicit target (not present in m_targets) | |||||
private Target m_implicitTarget; | |||||
///The name of the default target | |||||
private String m_defaultTarget; | |||||
///The base directory of project | |||||
private File m_baseDirectory; | |||||
///The project name | |||||
private String m_name; | |||||
/** | |||||
* @return the project name. | |||||
*/ | |||||
public String getProjectName() | |||||
{ | |||||
return m_name; | |||||
} | |||||
/** | |||||
* Sets the project name. | |||||
* @param name the project name | |||||
*/ | |||||
public void setProjectName( String name ) | |||||
{ | |||||
m_name = name; | |||||
} | |||||
/** | |||||
* Get the imports for project. | |||||
* | |||||
* @return the imports | |||||
*/ | |||||
public TypeLib[] getTypeLibs() | |||||
{ | |||||
return (TypeLib[])m_imports.toArray( new TypeLib[ 0 ] ); | |||||
} | |||||
/** | |||||
* Get names of projects referred to by this project. | |||||
* | |||||
* @return the names | |||||
*/ | |||||
public String[] getProjectNames() | |||||
{ | |||||
return (String[])m_projects.keySet().toArray( new String[ 0 ] ); | |||||
} | |||||
/** | |||||
* Retrieve project reffered to by this project. | |||||
* | |||||
* @param name the project name | |||||
* @return the Project or null if none by that name | |||||
*/ | |||||
public Project getProject( final String name ) | |||||
{ | |||||
return (Project)m_projects.get( name ); | |||||
} | |||||
/** | |||||
* Retrieve base directory of project. | |||||
* | |||||
* @return the projects base directory | |||||
*/ | |||||
public final File getBaseDirectory() | |||||
{ | |||||
return m_baseDirectory; | |||||
} | |||||
/** | |||||
* Retrieve implicit target. | |||||
* The implicit target contains all the top level tasks. | |||||
* | |||||
* @return the Target | |||||
*/ | |||||
public final Target getImplicitTarget() | |||||
{ | |||||
return m_implicitTarget; | |||||
} | |||||
/** | |||||
* Set ImplicitTarget. | |||||
* | |||||
* @param target the implicit target | |||||
*/ | |||||
public final void setImplicitTarget( final Target target ) | |||||
{ | |||||
m_implicitTarget = target; | |||||
} | |||||
/** | |||||
* Retrieve a target by name. | |||||
* | |||||
* @param targetName the name of target | |||||
* @return the Target or null if no target exists with name | |||||
*/ | |||||
public final Target getTarget( final String targetName ) | |||||
{ | |||||
return (Target)m_targets.get( targetName ); | |||||
} | |||||
/** | |||||
* Get name of default target. | |||||
* | |||||
* @return the default target name | |||||
*/ | |||||
public final String getDefaultTargetName() | |||||
{ | |||||
return m_defaultTarget; | |||||
} | |||||
/** | |||||
* Retrieve names of all targets in project. | |||||
* | |||||
* @return an array target names | |||||
*/ | |||||
public final String[] getTargetNames() | |||||
{ | |||||
return (String[])m_targets.keySet().toArray( new String[ 0 ] ); | |||||
} | |||||
/** | |||||
* Set DefaultTargetName. | |||||
* | |||||
* @param defaultTarget the default target name | |||||
*/ | |||||
public final void setDefaultTargetName( final String defaultTarget ) | |||||
{ | |||||
m_defaultTarget = defaultTarget; | |||||
} | |||||
/** | |||||
* Sets the project base directory. | |||||
* @param baseDirectory the base directory for the project | |||||
*/ | |||||
public final void setBaseDirectory( final File baseDirectory ) | |||||
{ | |||||
m_baseDirectory = baseDirectory; | |||||
} | |||||
/** | |||||
* Adds a type library import to the project. | |||||
* @param typeLib the type library | |||||
*/ | |||||
public final void addTypeLib( final TypeLib typeLib ) | |||||
{ | |||||
m_imports.add( typeLib ); | |||||
} | |||||
/** | |||||
* Add a target. | |||||
* | |||||
* @param name the name of target | |||||
* @param target the Target | |||||
* @exception IllegalArgumentException if target already exists with same name | |||||
*/ | |||||
public final void addTarget( final String name, final Target target ) | |||||
{ | |||||
if( null != m_targets.get( name ) ) | |||||
{ | |||||
final String message = REZ.getString( "duplicate-target.error", name ); | |||||
throw new IllegalArgumentException( message ); | |||||
} | |||||
else | |||||
{ | |||||
m_targets.put( name, target ); | |||||
} | |||||
} | |||||
/** | |||||
* Add a project reference. | |||||
* | |||||
* @param name the name of target | |||||
* @param project the Project | |||||
* @exception IllegalArgumentException if project already exists with same name | |||||
*/ | |||||
public final void addProject( final String name, final Project project ) | |||||
{ | |||||
if( null != m_projects.get( name ) ) | |||||
{ | |||||
final String message = REZ.getString( "duplicate-project.error", name ); | |||||
throw new IllegalArgumentException( message ); | |||||
} | |||||
else | |||||
{ | |||||
m_projects.put( name, project ); | |||||
} | |||||
} | |||||
} |
@@ -1,553 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.builder; | |||||
import java.io.File; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import javax.xml.parsers.SAXParser; | |||||
import javax.xml.parsers.SAXParserFactory; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.excalibur.io.FileUtil; | |||||
import org.apache.avalon.excalibur.util.StringUtil; | |||||
import org.apache.avalon.framework.Version; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.myrmidon.interfaces.builder.ProjectBuilder; | |||||
import org.apache.myrmidon.interfaces.builder.ProjectException; | |||||
import org.apache.myrmidon.interfaces.model.DefaultNameValidator; | |||||
import org.apache.myrmidon.interfaces.model.Dependency; | |||||
import org.apache.myrmidon.interfaces.model.Project; | |||||
import org.apache.myrmidon.interfaces.model.Target; | |||||
import org.apache.myrmidon.interfaces.model.TypeLib; | |||||
import org.xml.sax.XMLReader; | |||||
/** | |||||
* Default implementation to construct project from a build file. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
* | |||||
* @ant.type type="project-builder" name="ant2" | |||||
*/ | |||||
public class DefaultProjectBuilder | |||||
extends AbstractLogEnabled | |||||
implements ProjectBuilder | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultProjectBuilder.class ); | |||||
private static final Version VERSION = new Version( 2, 0, 0 ); | |||||
private static final int PROJECT_REFERENCES = 0; | |||||
private static final int LIBRARY_IMPORTS = 1; | |||||
private static final int IMPLICIT_TASKS = 2; | |||||
private static final int TARGETS = 3; | |||||
// Use a name validator with the default rules. | |||||
private DefaultNameValidator m_nameValidator = new DefaultNameValidator(); | |||||
/** | |||||
* build a project from file. | |||||
* | |||||
* @param source the source | |||||
* @return the constructed Project | |||||
* @exception ProjectException if an error occurs | |||||
*/ | |||||
public Project build( final String source ) | |||||
throws ProjectException | |||||
{ | |||||
final File file = new File( source ); | |||||
return build( file, new HashMap() ); | |||||
} | |||||
private Project build( final File file, final HashMap projects ) | |||||
throws ProjectException | |||||
{ | |||||
try | |||||
{ | |||||
// Check for cached project | |||||
final String systemID = extractURL( file ); | |||||
final Project result = (Project)projects.get( systemID ); | |||||
if( null != result ) | |||||
{ | |||||
return result; | |||||
} | |||||
// Parse the project file | |||||
final Configuration configuration = parseProject( systemID ); | |||||
// Build the project model and add to cache | |||||
final DefaultProject project = buildProject( file, configuration ); | |||||
projects.put( systemID, project ); | |||||
// Build using all top-level attributes | |||||
buildTopLevelProject( project, configuration, projects ); | |||||
return project; | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "ant.project-build.error", | |||||
file.getAbsolutePath() ); | |||||
throw new ProjectException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Builds a project configuration from a build file. | |||||
* @param systemID the XML system id of the build file | |||||
* @return the project configuration | |||||
* @throws ProjectException on parse error | |||||
*/ | |||||
protected Configuration parseProject( final String systemID ) | |||||
throws ProjectException | |||||
{ | |||||
try | |||||
{ | |||||
final SAXConfigurationHandler handler = new SAXConfigurationHandler(); | |||||
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||||
final SAXParser saxParser = saxParserFactory.newSAXParser(); | |||||
final XMLReader parser = saxParser.getXMLReader(); | |||||
parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false ); | |||||
parser.setFeature( "http://xml.org/sax/features/namespaces", false ); | |||||
//parser.setFeature( "http://xml.org/sax/features/validation", false ); | |||||
parser.setContentHandler( handler ); | |||||
parser.setErrorHandler( handler ); | |||||
parser.parse( systemID ); | |||||
return handler.getConfiguration(); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "ant.project-parse.error" ); | |||||
throw new ProjectException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* build project from configuration. | |||||
* | |||||
* @param file the file from which configuration was loaded | |||||
* @param configuration the configuration loaded | |||||
* @return the created Project | |||||
* @exception ProjectException if an error occurs building the project | |||||
*/ | |||||
private DefaultProject buildProject( final File file, | |||||
final Configuration configuration ) | |||||
throws ProjectException | |||||
{ | |||||
if( !configuration.getName().equals( "project" ) ) | |||||
{ | |||||
final String message = REZ.getString( "ant.no-project-element.error" ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
//get project-level attributes | |||||
final String projectName = getProjectName( configuration, file ); | |||||
final String baseDirectoryName = configuration.getAttribute( "basedir", null ); | |||||
final String defaultTarget = configuration.getAttribute( "default", "main" ); | |||||
final Version version = getVersion( configuration ); | |||||
if( !VERSION.complies( version ) ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.bad-version.error", VERSION, version ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
//determine base directory for project. Use the directory containing | |||||
//the build file as the default. | |||||
File baseDirectory = file.getParentFile(); | |||||
if( baseDirectoryName != null ) | |||||
{ | |||||
baseDirectory = FileUtil.resolveFile( baseDirectory, baseDirectoryName ); | |||||
} | |||||
baseDirectory = baseDirectory.getAbsoluteFile(); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( "ant.project-banner.notice", | |||||
file, baseDirectory ); | |||||
getLogger().debug( message ); | |||||
} | |||||
//create project and ... | |||||
final DefaultProject project = new DefaultProject(); | |||||
project.setProjectName( projectName ); | |||||
project.setDefaultTargetName( defaultTarget ); | |||||
project.setBaseDirectory( baseDirectory ); | |||||
return project; | |||||
} | |||||
/** | |||||
* Get the project name from the configuration, or create a default name if none | |||||
* was supplied. | |||||
*/ | |||||
private String getProjectName( final Configuration configuration, | |||||
final File file ) | |||||
throws ProjectException | |||||
{ | |||||
String projectName = configuration.getAttribute( "name", null ); | |||||
if( projectName == null ) | |||||
{ | |||||
// Create a name based on the file name. | |||||
String fileNameBase = FileUtil.removeExtension( file.getName() ); | |||||
try | |||||
{ | |||||
projectName = m_nameValidator.makeValidName( fileNameBase ); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
String message = REZ.getString( "ant.project-create-name.error" ); | |||||
throw new ProjectException( message, e ); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
// Make sure the supplied name is valid. | |||||
try | |||||
{ | |||||
m_nameValidator.validate( projectName ); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
String message = REZ.getString( "ant.project-bad-name.error" ); | |||||
throw new ProjectException( message, e ); | |||||
} | |||||
} | |||||
return projectName; | |||||
} | |||||
/** | |||||
* Retrieve the version attribute from the specified configuration element. | |||||
* Throw exceptions with meaningful errors if malformed or missing. | |||||
*/ | |||||
private Version getVersion( final Configuration configuration ) | |||||
throws ProjectException | |||||
{ | |||||
try | |||||
{ | |||||
final String versionString = configuration.getAttribute( "version" ); | |||||
return parseVersion( versionString ); | |||||
} | |||||
catch( final ConfigurationException ce ) | |||||
{ | |||||
final String message = REZ.getString( "ant.version-missing.error" ); | |||||
throw new ProjectException( message, ce ); | |||||
} | |||||
} | |||||
/** | |||||
* Utility function to extract version | |||||
*/ | |||||
private Version parseVersion( final String versionString ) | |||||
throws ProjectException | |||||
{ | |||||
try | |||||
{ | |||||
return Version.getVersion( versionString ); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.malformed.version", versionString ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
} | |||||
/** | |||||
* Handle all top level elements in configuration. | |||||
* | |||||
* @param project the project | |||||
* @param configuration the Configuration | |||||
* @exception ProjectException if an error occurs | |||||
*/ | |||||
private void buildTopLevelProject( final DefaultProject project, | |||||
final Configuration configuration, | |||||
final HashMap projects ) | |||||
throws ProjectException | |||||
{ | |||||
final ArrayList implicitTaskList = new ArrayList(); | |||||
final Configuration[] children = configuration.getChildren(); | |||||
int state = PROJECT_REFERENCES; | |||||
for( int i = 0; i < children.length; i++ ) | |||||
{ | |||||
final Configuration element = children[ i ]; | |||||
final String name = element.getName(); | |||||
if( PROJECT_REFERENCES == state ) | |||||
{ | |||||
if( name.equals( "projectref" ) ) | |||||
{ | |||||
buildProjectRef( project, element, projects ); | |||||
continue; | |||||
} | |||||
else | |||||
{ | |||||
state = LIBRARY_IMPORTS; | |||||
} | |||||
} | |||||
if( LIBRARY_IMPORTS == state ) | |||||
{ | |||||
if( name.equals( "import" ) ) | |||||
{ | |||||
buildTypeLib( project, element ); | |||||
continue; | |||||
} | |||||
else | |||||
{ | |||||
state = IMPLICIT_TASKS; | |||||
} | |||||
} | |||||
if( IMPLICIT_TASKS == state ) | |||||
{ | |||||
//Check for any implicit tasks here | |||||
if( !name.equals( "target" ) ) | |||||
{ | |||||
implicitTaskList.add( element ); | |||||
continue; | |||||
} | |||||
else | |||||
{ | |||||
state = TARGETS; | |||||
} | |||||
} | |||||
if( name.equals( "target" ) ) | |||||
{ | |||||
buildTarget( project, element ); | |||||
} | |||||
else | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.unknown-toplevel-element.error", name, | |||||
element.getLocation() ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
} | |||||
final Configuration[] implicitTasks = | |||||
(Configuration[])implicitTaskList.toArray( new Configuration[ 0 ] ); | |||||
final Target implicitTarget = new Target( implicitTasks, null ); | |||||
project.setImplicitTarget( implicitTarget ); | |||||
} | |||||
private void buildProjectRef( final DefaultProject project, | |||||
final Configuration element, | |||||
final HashMap projects ) | |||||
throws ProjectException | |||||
{ | |||||
final String name = element.getAttribute( "name", null ); | |||||
final String location = element.getAttribute( "location", null ); | |||||
if( null == name ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.projectref-no-name.error", | |||||
element.getLocation() ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
try | |||||
{ | |||||
m_nameValidator.validate( name ); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.projectref-bad-name.error", | |||||
element.getLocation() ); | |||||
throw new ProjectException( message, e ); | |||||
} | |||||
if( null == location ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.projectref-no-location.error", | |||||
element.getLocation() ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
// Build the URL of the referenced projects | |||||
final File baseDirectory = project.getBaseDirectory(); | |||||
final File file = FileUtil.resolveFile( baseDirectory, location ); | |||||
// Locate the referenced project, building it if necessary | |||||
final Project other = build( file, projects ); | |||||
// Add the reference | |||||
project.addProject( name, other ); | |||||
} | |||||
/** | |||||
* Validates a project file name, and builds the canonical URL for it. | |||||
*/ | |||||
private String extractURL( final File file ) throws ProjectException | |||||
{ | |||||
if( ! file.isFile() ) | |||||
{ | |||||
final String message = REZ.getString( "ant.no-project-file.error" ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
try | |||||
{ | |||||
return file.getCanonicalFile().toURL().toString(); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "ant.project-unexpected.error" ); | |||||
throw new ProjectException( message, e ); | |||||
} | |||||
} | |||||
private void buildTypeLib( final DefaultProject project, | |||||
final Configuration element ) | |||||
throws ProjectException | |||||
{ | |||||
final String library = element.getAttribute( "library", null ); | |||||
final String name = element.getAttribute( "name", null ); | |||||
final String type = element.getAttribute( "type", null ); | |||||
if( null == library ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.import-no-library.error", element.getLocation() ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
if( null == name || null == type ) | |||||
{ | |||||
if( null != name || null != type ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.import-malformed.error", element.getLocation() ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
} | |||||
project.addTypeLib( new TypeLib( library, type, name ) ); | |||||
} | |||||
/** | |||||
* Build a target from configuration. | |||||
* | |||||
* @param project the project | |||||
* @param target the Configuration | |||||
*/ | |||||
private void buildTarget( final DefaultProject project, final Configuration target ) | |||||
throws ProjectException | |||||
{ | |||||
final String name = target.getAttribute( "name", null ); | |||||
final String depends = target.getAttribute( "depends", null ); | |||||
verifyTargetName( name, target ); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( "ant.target-parse.notice", name ); | |||||
getLogger().debug( message ); | |||||
} | |||||
final Dependency[] dependencies = buildDependsList( depends, target ); | |||||
final Target defaultTarget = new Target( target.getChildren(), dependencies ); | |||||
//add target to project | |||||
project.addTarget( name, defaultTarget ); | |||||
} | |||||
private void verifyTargetName( final String name, final Configuration target ) | |||||
throws ProjectException | |||||
{ | |||||
if( null == name ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.target-noname.error", target.getLocation() ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
try | |||||
{ | |||||
m_nameValidator.validate( name ); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "ant.target-bad-name.error", target.getLocation() ); | |||||
throw new ProjectException( message, e ); | |||||
} | |||||
} | |||||
private Dependency[] buildDependsList( final String depends, | |||||
final Configuration target ) | |||||
throws ProjectException | |||||
{ | |||||
//apply depends attribute | |||||
if( null == depends ) | |||||
{ | |||||
return null; | |||||
} | |||||
final String[] elements = StringUtil.split( depends, "," ); | |||||
final ArrayList dependsList = new ArrayList(); | |||||
for( int i = 0; i < elements.length; i++ ) | |||||
{ | |||||
final String dependency = elements[ i ].trim(); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( "ant.target-dependency.notice", | |||||
dependency ); | |||||
getLogger().debug( message ); | |||||
} | |||||
// Split project->target dependencies | |||||
final int sep = dependency.indexOf( "->" ); | |||||
final String projectName; | |||||
final String targetName; | |||||
if( sep != -1 ) | |||||
{ | |||||
projectName = dependency.substring( 0, sep ); | |||||
targetName = dependency.substring( sep + 2 ); | |||||
} | |||||
else | |||||
{ | |||||
projectName = null; | |||||
targetName = dependency; | |||||
} | |||||
if( targetName.length() == 0 || | |||||
( projectName != null && projectName.length() == 0 ) ) | |||||
{ | |||||
final String message = REZ.getString( "ant.target-bad-dependency.error", | |||||
target.getName(), | |||||
target.getLocation() ); | |||||
throw new ProjectException( message ); | |||||
} | |||||
dependsList.add( new Dependency( projectName, targetName ) ); | |||||
} | |||||
return (Dependency[])dependsList.toArray( new Dependency[dependsList.size() ] ); | |||||
} | |||||
} |
@@ -1,60 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.builder; | |||||
import java.util.ArrayList; | |||||
import org.xml.sax.Attributes; | |||||
import org.xml.sax.SAXException; | |||||
import org.xml.sax.helpers.DefaultHandler; | |||||
/** | |||||
* Handler that reacts to PIs before first element. | |||||
* Have to do it this way as there doesn't seem to be a *safe* way | |||||
* of redirecting content handlers at runtime while using transformers. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class ReactorPIHandler | |||||
extends DefaultHandler | |||||
{ | |||||
private ArrayList m_targets = new ArrayList(); | |||||
private ArrayList m_data = new ArrayList(); | |||||
public int getPICount() | |||||
{ | |||||
return m_targets.size(); | |||||
} | |||||
public String getTarget( final int index ) | |||||
{ | |||||
return (String)m_targets.get( index ); | |||||
} | |||||
public String getData( final int index ) | |||||
{ | |||||
return (String)m_data.get( index ); | |||||
} | |||||
public void processingInstruction( final String target, final String data ) | |||||
throws SAXException | |||||
{ | |||||
m_targets.add( target ); | |||||
m_data.add( data ); | |||||
} | |||||
public void startElement( final String uri, | |||||
final String localName, | |||||
final String qName, | |||||
final Attributes atts ) | |||||
throws SAXException | |||||
{ | |||||
//Workaround to stop SAX pipeline | |||||
throw new StopParsingException(); | |||||
} | |||||
} |
@@ -1,37 +0,0 @@ | |||||
ati.two.stylesheet.pis=Build file can not contain two xsl-stylesheet PIs. | |||||
ati.params.error=Malformed PI: expected <?xsl-params location=\"myparams.properties\"?> | |||||
ati.param.error=Malformed PI: expected <?xsl-param name=\"foo\" value=\"bar\"?> | |||||
ati.style.error=Malformed PI: expected <?xsl-params href=\"mystylesheet.xsl\"?> | |||||
ati.loading-params.error=Error loading parameters {0}. Reason: {1}. | |||||
ati.loading-style.error=Error locating stylesheet {0}. Reason: {1}. | |||||
ati.attribue-expected.error=Expecting an attribute but received {0}. | |||||
ati.attribue-unquoted.error=Expecting the value of attribute {0} to be enclosed in quotes. | |||||
ant.project-banner.notice=Project {0} base directory: {1}. | |||||
ant.target-parse.notice=Parsing target: {0}. | |||||
ant.target-dependency.notice=Target dependency: {0} | |||||
ant.project-unexpected.error=Unexpected error building project. | |||||
ant.project-parse.error=Could not parse project file. | |||||
ant.project-build.error=Could not load project from "{0}". | |||||
ant.no-project-element.error=Project file must be enclosed in project element. | |||||
ant.unknown-toplevel-element.error=Unknown top-level element {0} at {1}. | |||||
ant.project-bad-name.error=Invalid project name. | |||||
ant.project-create-name.error=Could not create a name for this project. | |||||
ant.projectref-no-name.error=Malformed projectref without a name attribute at {0}. | |||||
ant.projectref-bad-name.error=Projectref with an invalid name attribute at {0}. | |||||
ant.projectref-no-location.error=Malformed projectref without a location attribute at {0}. | |||||
ant.import-no-library.error=Malformed import without a library attribute at {0}. | |||||
ant.import-malformed.error=Malformed import at {0}. If name or type attribute is specified, both attributes must be specified. | |||||
ant.target-noname.error=Discovered un-named target at {0}. | |||||
ant.target-bad-name.error=Target with an invalid name at {0}. | |||||
ant.target-bad-dependency.error=Discovered empty dependency in target {0} at {1}. | |||||
ant.malformed.version=Project has an invalid version "{0}". | |||||
ant.version-missing.error=Project has no version attribute. | |||||
ant.bad-version.error=Incompatible build file version detected. Expected version {0} but found version {1}. | |||||
ant.no-project-file.error=Project file does not exist, or is not a file. | |||||
ant.project-convert.notice=Applying compatibility stylesheet to project file. | |||||
ant.project-convert.error=Error converting build file. | |||||
duplicate-project.error=Can not have two projects referenced in a file with the name {0}. | |||||
duplicate-target.error=Can not have two targets in a file with the name {0}. |
@@ -1,25 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.builder; | |||||
import org.xml.sax.SAXException; | |||||
/** | |||||
* Dummy exception to stop parsing "safely". | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class StopParsingException | |||||
extends SAXException | |||||
{ | |||||
public StopParsingException() | |||||
{ | |||||
super( "" ); | |||||
} | |||||
} |
@@ -1,97 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.builder; | |||||
import java.io.InputStream; | |||||
import javax.xml.transform.Result; | |||||
import javax.xml.transform.Source; | |||||
import javax.xml.transform.Transformer; | |||||
import javax.xml.transform.TransformerConfigurationException; | |||||
import javax.xml.transform.TransformerFactory; | |||||
import javax.xml.transform.sax.SAXResult; | |||||
import javax.xml.transform.stream.StreamSource; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||||
import org.apache.myrmidon.interfaces.builder.ProjectException; | |||||
/** | |||||
* A Project Builder which performs an XSL transformation on a project. | |||||
* | |||||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
* @version $Revision$ $Date$ | |||||
* | |||||
* @ant.type type="project-builder" name="ant-transform" | |||||
*/ | |||||
public class TransformingProjectBuilder | |||||
extends DefaultProjectBuilder | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( TransformingProjectBuilder.class ); | |||||
private static final String STYLESHEET = "ant1convert.xsl"; | |||||
private Transformer m_transformer; | |||||
/** | |||||
* Builds a project Configuration from a project file, applying the | |||||
* ant1 conversion stylesheet. | |||||
* @param systemID the XML system id for the project file | |||||
* @return the project configuration | |||||
* @throws ProjectException if a parse error occurs | |||||
*/ | |||||
protected Configuration parseProject( String systemID ) | |||||
throws ProjectException | |||||
{ | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( "ant.project-convert.notice" ); | |||||
getLogger().debug( message ); | |||||
} | |||||
try | |||||
{ | |||||
// Create a XSLT source for the build file. | |||||
Source source = new StreamSource( systemID ); | |||||
// Create a configuration handler for the output. | |||||
final SAXConfigurationHandler handler = new SAXConfigurationHandler(); | |||||
Result result = new SAXResult( handler ); | |||||
// Perform the transformation. | |||||
getTransformer().transform( source, result ); | |||||
return handler.getConfiguration(); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
throw new ProjectException( REZ.getString( "ant.project-convert.error" ), | |||||
e ); | |||||
} | |||||
} | |||||
/** | |||||
* Lazy load a Transformer with the conversion stylesheet. | |||||
* @return the initialised Transformer | |||||
* @throws TransformerConfigurationException | |||||
*/ | |||||
private Transformer getTransformer() | |||||
throws TransformerConfigurationException | |||||
{ | |||||
// Lazy loading of stylesheet source. | |||||
if( m_transformer == null ) | |||||
{ | |||||
InputStream stylesheet = | |||||
this.getClass().getResourceAsStream( STYLESHEET ); | |||||
StreamSource stylesheetSource = new StreamSource( stylesheet ); | |||||
TransformerFactory xformFactory = TransformerFactory.newInstance(); | |||||
m_transformer = xformFactory.newTransformer( stylesheetSource ); | |||||
} | |||||
return m_transformer; | |||||
} | |||||
} |
@@ -1,151 +0,0 @@ | |||||
<?xml version="1.0"?> | |||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> | |||||
<xsl:output method="xml" indent="yes"/> | |||||
<xsl:template match="/project"> | |||||
<xsl:comment>Converted Project file.</xsl:comment> | |||||
<xsl:copy> | |||||
<xsl:attribute name="version">2.0</xsl:attribute> | |||||
<xsl:apply-templates select="@*[name() != 'version']" mode="copy"/> | |||||
<xsl:apply-templates/> | |||||
</xsl:copy> | |||||
</xsl:template> | |||||
<!-- For projects with a version attribute, simply copy the entire tree. --> | |||||
<!-- TODO check for version >= 2.0.0 --> | |||||
<xsl:template match="/project[@version]"> | |||||
<xsl:comment>Copied Project file.</xsl:comment> | |||||
<xsl:copy> | |||||
<xsl:apply-templates select="@*"/> | |||||
<xsl:apply-templates mode="copy"/> | |||||
</xsl:copy> | |||||
</xsl:template> | |||||
<!-- Handle simple target nodes --> | |||||
<xsl:template match="/project/target"> | |||||
<xsl:copy> | |||||
<xsl:apply-templates select="@*"/> | |||||
<xsl:apply-templates/> | |||||
</xsl:copy> | |||||
</xsl:template> | |||||
<!-- Handle target nodes with 'if' --> | |||||
<xsl:template match="/project/target[@if]"> | |||||
<xsl:copy> | |||||
<xsl:apply-templates select="@*[name() != 'if']"/> | |||||
<!-- Put in the if condition --> | |||||
<xsl:element name="if"> | |||||
<xsl:element name="condition"> | |||||
<xsl:element name="is-set"> | |||||
<xsl:attribute name="property"> | |||||
<xsl:value-of select="@if"/> | |||||
</xsl:attribute> | |||||
</xsl:element> | |||||
</xsl:element> | |||||
<!-- Now add the target content --> | |||||
<xsl:apply-templates/> | |||||
</xsl:element> | |||||
</xsl:copy> | |||||
</xsl:template> | |||||
<!-- Handle target nodes with 'unless' --> | |||||
<xsl:template match="/project/target[@unless]"> | |||||
<xsl:copy> | |||||
<xsl:apply-templates select="@*[name() != 'unless']"/> | |||||
<!-- Put in the unless condition --> | |||||
<xsl:element name="if"> | |||||
<xsl:element name="condition"> | |||||
<xsl:element name="not"> | |||||
<xsl:element name="is-set"> | |||||
<xsl:attribute name="property"> | |||||
<xsl:value-of select="@unless"/> | |||||
</xsl:attribute> | |||||
</xsl:element> | |||||
</xsl:element> | |||||
</xsl:element> | |||||
<!-- Now add the target content --> | |||||
<xsl:apply-templates/> | |||||
</xsl:element> | |||||
</xsl:copy> | |||||
</xsl:template> | |||||
<!-- Handle target nodes with 'if' and 'unless' --> | |||||
<xsl:template match="/project/target[@if and @unless]"> | |||||
<xsl:copy> | |||||
<xsl:apply-templates select="@*[name()!='if' and name()!='unless']"/> | |||||
<!-- Put in the 'if' condition --> | |||||
<xsl:element name="if"> | |||||
<xsl:element name="condition"> | |||||
<xsl:element name="is-set"> | |||||
<xsl:attribute name="property"> | |||||
<xsl:value-of select="@if"/> | |||||
</xsl:attribute> | |||||
</xsl:element> | |||||
</xsl:element> | |||||
<!-- Put in the 'unless' condition --> | |||||
<xsl:element name="if"> | |||||
<xsl:element name="condition"> | |||||
<xsl:element name="not"> | |||||
<xsl:element name="is-set"> | |||||
<xsl:attribute name="property"> | |||||
<xsl:value-of select="@unless"/> | |||||
</xsl:attribute> | |||||
</xsl:element> | |||||
</xsl:element> | |||||
</xsl:element> | |||||
<!-- Now add the target content --> | |||||
<xsl:apply-templates/> | |||||
</xsl:element> | |||||
</xsl:element> | |||||
</xsl:copy> | |||||
</xsl:template> | |||||
<!-- Handle task nodes, prepending "ant1." --> | |||||
<xsl:template match="*"> | |||||
<xsl:element name="ant1.{name()}"> | |||||
<xsl:apply-templates select="@*"/> | |||||
<xsl:apply-templates mode="copy"/> | |||||
</xsl:element> | |||||
</xsl:template> | |||||
<!-- Copy all elements in copy-mode --> | |||||
<xsl:template match="*" mode="copy"> | |||||
<xsl:copy> | |||||
<xsl:apply-templates select="@*"/> | |||||
<xsl:apply-templates mode="copy"/> | |||||
</xsl:copy> | |||||
</xsl:template> | |||||
<!-- Always copy attributes --> | |||||
<xsl:template match="@*"> | |||||
<xsl:copy/> | |||||
</xsl:template> | |||||
<xsl:template match="@*" mode="copy"> | |||||
<xsl:copy/> | |||||
</xsl:template> | |||||
<!-- Always copy comments --> | |||||
<xsl:template match="comment()"> | |||||
<xsl:copy/> | |||||
</xsl:template> | |||||
<xsl:template match="comment()" mode="copy"> | |||||
<xsl:copy/> | |||||
</xsl:template> | |||||
</xsl:stylesheet> | |||||
@@ -1,305 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.classloader; | |||||
import java.io.File; | |||||
import java.net.MalformedURLException; | |||||
import java.net.URL; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.HashSet; | |||||
import java.util.Map; | |||||
import java.util.Set; | |||||
import java.util.jar.JarFile; | |||||
import java.util.jar.Manifest; | |||||
import org.apache.aut.nativelib.PathUtil; | |||||
import org.apache.avalon.excalibur.extension.Extension; | |||||
import org.apache.avalon.excalibur.extension.OptionalPackage; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.context.Context; | |||||
import org.apache.avalon.framework.context.ContextException; | |||||
import org.apache.avalon.framework.context.Contextualizable; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.interfaces.classloader.ClassLoaderException; | |||||
import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||||
/** | |||||
* A default implementation of a ClassLoader manager. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultClassLoaderManager | |||||
extends AbstractLogEnabled | |||||
implements ClassLoaderManager, Serviceable, Contextualizable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultClassLoaderManager.class ); | |||||
/** | |||||
* Map from File/ArrayList to the ClassLoader for that file/files. | |||||
*/ | |||||
private final Map m_classLoaders = new HashMap(); | |||||
private ExtensionManager m_extensionManager; | |||||
private ClassLoader m_commonClassLoader; | |||||
public DefaultClassLoaderManager() | |||||
{ | |||||
} | |||||
public DefaultClassLoaderManager( final ClassLoader commonClassLoader ) | |||||
{ | |||||
m_commonClassLoader = commonClassLoader; | |||||
} | |||||
public void contextualize( final Context context ) throws ContextException | |||||
{ | |||||
if( null == m_commonClassLoader ) | |||||
{ | |||||
m_commonClassLoader = (ClassLoader)context.get( "myrmidon.shared.classloader" ); | |||||
} | |||||
} | |||||
/** | |||||
* Retrieve relevent services needed to deploy. | |||||
*/ | |||||
public void service( final ServiceManager serviceManager ) | |||||
throws ServiceException | |||||
{ | |||||
m_extensionManager = (ExtensionManager)serviceManager.lookup( ExtensionManager.ROLE ); | |||||
} | |||||
/** | |||||
* Returns the common ClassLoader. This is the parent of all classloaders | |||||
* built by this ClassLoaderManager. | |||||
*/ | |||||
public ClassLoader getCommonClassLoader() | |||||
{ | |||||
return m_commonClassLoader; | |||||
} | |||||
/** | |||||
* Creates a class loader for a Jar file. | |||||
*/ | |||||
public ClassLoader getClassLoader( final File file ) throws ClassLoaderException | |||||
{ | |||||
try | |||||
{ | |||||
final File canonFile = file.getCanonicalFile(); | |||||
// Check for cached classloader, creating it if required | |||||
ClassLoader loader = (ClassLoader)m_classLoaders.get( canonFile ); | |||||
if( loader == null ) | |||||
{ | |||||
checkFile( canonFile ); | |||||
final OptionalPackage optionalPackage = toOptionalPackage( canonFile ); | |||||
loader = buildClassLoader( optionalPackage, new HashSet() ); | |||||
} | |||||
return loader; | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "create-classloader-for-file.error", file ); | |||||
throw new ClassLoaderException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Creates a class loader for a set of Jar files. | |||||
*/ | |||||
public ClassLoader createClassLoader( final File[] files ) throws ClassLoaderException | |||||
{ | |||||
try | |||||
{ | |||||
if( files == null || files.length == 0 ) | |||||
{ | |||||
return m_commonClassLoader; | |||||
} | |||||
// Build a list of optional packages for the files | |||||
final OptionalPackage[] packages = new OptionalPackage[ files.length ]; | |||||
for( int i = 0; i < files.length; i++ ) | |||||
{ | |||||
final File canonFile = files[ i ].getCanonicalFile(); | |||||
checkFile( canonFile ); | |||||
packages[ i ] = toOptionalPackage( canonFile ); | |||||
} | |||||
// Build the classloaders for the required extensions | |||||
final ClassLoader[] parentClassLoaders = buildParentClassLoaders( packages, new HashSet() ); | |||||
// Build the classloader | |||||
final URL[] urls = buildClasspath( files ); | |||||
return new MultiParentURLClassLoader( urls, parentClassLoaders ); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String fileNames = PathUtil.formatPath( files ); | |||||
final String message = REZ.getString( "create-classloader-for-files.error", fileNames ); | |||||
throw new ClassLoaderException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Builds the classloader for an optional package. | |||||
*/ | |||||
private ClassLoader buildClassLoader( final OptionalPackage pkg, | |||||
final Set pending ) | |||||
throws Exception | |||||
{ | |||||
final File jarFile = pkg.getFile(); | |||||
// Check for cached classloader | |||||
ClassLoader classLoader = (ClassLoader)m_classLoaders.get( jarFile ); | |||||
if( classLoader != null ) | |||||
{ | |||||
return classLoader; | |||||
} | |||||
// Check for cyclic dependency | |||||
if( pending.contains( jarFile ) ) | |||||
{ | |||||
final String message = REZ.getString( "dependency-cycle.error", jarFile ); | |||||
throw new Exception( message ); | |||||
} | |||||
pending.add( jarFile ); | |||||
// Build the classloaders for the extensions required by this optional | |||||
// package | |||||
final ClassLoader[] parentClassLoaders = | |||||
buildParentClassLoaders( new OptionalPackage[] { pkg }, pending ); | |||||
// Create and cache the classloader | |||||
final URL[] urls = { jarFile.toURL() }; | |||||
classLoader = new MultiParentURLClassLoader( urls, parentClassLoaders ); | |||||
m_classLoaders.put( jarFile, classLoader ); | |||||
pending.remove( jarFile ); | |||||
return classLoader; | |||||
} | |||||
/** | |||||
* Builds the parent classloaders for a set of optional packages. That is, | |||||
* the classloaders for all of the extensions required by the given set | |||||
* of optional packages. | |||||
*/ | |||||
private ClassLoader[] buildParentClassLoaders( final OptionalPackage[] packages, | |||||
final Set pending ) | |||||
throws Exception | |||||
{ | |||||
final ArrayList classLoaders = new ArrayList(); | |||||
// Include the common class loader | |||||
classLoaders.add( m_commonClassLoader ); | |||||
// Build the classloader for each optional package, filtering out duplicates | |||||
for( int i = 0; i < packages.length; i++ ) | |||||
{ | |||||
final OptionalPackage optionalPackage = packages[ i ]; | |||||
// Locate the dependencies for this jar file | |||||
final OptionalPackage[] requiredPackages = getOptionalPackagesFor( optionalPackage ); | |||||
// Build the classloader for the package | |||||
for( int j = 0; j < requiredPackages.length; j++ ) | |||||
{ | |||||
final OptionalPackage requiredPackage = requiredPackages[j ]; | |||||
final ClassLoader classLoader = buildClassLoader( requiredPackage, pending ); | |||||
if( ! classLoaders.contains( classLoader ) ) | |||||
{ | |||||
classLoaders.add( classLoader ); | |||||
} | |||||
} | |||||
} | |||||
return (ClassLoader[])classLoaders.toArray( new ClassLoader[classLoaders.size() ] ); | |||||
} | |||||
/** | |||||
* Assembles a set of files into a URL classpath. | |||||
*/ | |||||
private URL[] buildClasspath( final File[] files ) | |||||
throws MalformedURLException | |||||
{ | |||||
final URL[] urls = new URL[ files.length ]; | |||||
for( int i = 0; i < files.length; i++ ) | |||||
{ | |||||
urls[ i ] = files[i ].toURL(); | |||||
} | |||||
return urls; | |||||
} | |||||
/** | |||||
* Builds an OptionalPackage for a Jar file. | |||||
* | |||||
* @param file the jar. | |||||
*/ | |||||
private OptionalPackage toOptionalPackage( final File file ) | |||||
throws Exception | |||||
{ | |||||
// Determine the extensions required by this file | |||||
final JarFile jarFile = new JarFile( file ); | |||||
final Manifest manifest = jarFile.getManifest(); | |||||
final Extension[] required = Extension.getRequired( manifest ); | |||||
return new OptionalPackage( file, new Extension[0], required ); | |||||
} | |||||
/** | |||||
* Locates the optional packages required by an optional package. | |||||
*/ | |||||
private OptionalPackage[] getOptionalPackagesFor( final OptionalPackage pkg ) | |||||
throws Exception | |||||
{ | |||||
// Locate the optional packages that provide the required extesions | |||||
final Extension[] required = pkg.getRequiredExtensions(); | |||||
final ArrayList packages = new ArrayList(); | |||||
for( int i = 0; i < required.length; i++ ) | |||||
{ | |||||
final Extension extension = required[i ]; | |||||
final OptionalPackage optionalPackage = m_extensionManager.getOptionalPackage( extension ); | |||||
if( optionalPackage == null ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "unsatisfied.extension.error", | |||||
pkg.getFile(), | |||||
extension.getExtensionName(), | |||||
extension.getSpecificationVersion() ); | |||||
throw new Exception( message ); | |||||
} | |||||
packages.add( optionalPackage ); | |||||
} | |||||
return (OptionalPackage[])packages.toArray( new OptionalPackage[packages.size() ] ); | |||||
} | |||||
/** | |||||
* Ensures a file exists and is not a directory. | |||||
*/ | |||||
private void checkFile( final File file ) | |||||
throws DeploymentException | |||||
{ | |||||
if( !file.exists() ) | |||||
{ | |||||
final String message = REZ.getString( "no-file.error", file ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
if( file.isDirectory() ) | |||||
{ | |||||
final String message = REZ.getString( "file-is-dir.error", file ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
} | |||||
} |
@@ -1,141 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.classloader; | |||||
import java.io.IOException; | |||||
import java.net.URL; | |||||
import java.net.URLClassLoader; | |||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
import java.util.Enumeration; | |||||
import java.util.List; | |||||
import java.util.Set; | |||||
import java.util.HashSet; | |||||
/** | |||||
* A URLClassLoader with more than one parent. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class MultiParentURLClassLoader | |||||
extends URLClassLoader | |||||
{ | |||||
private final ClassLoader[] m_parents; | |||||
/** | |||||
* Constructs a new URLClassLoader for the given URLs. | |||||
* | |||||
* @param urls the URLs from which to load classes and resources | |||||
* @param parents the parent class loaderer for delegation | |||||
*/ | |||||
public MultiParentURLClassLoader( final URL[] urls, final ClassLoader[] parents ) | |||||
{ | |||||
super( urls ); | |||||
m_parents = parents; | |||||
} | |||||
/** | |||||
* Finds a class. | |||||
* | |||||
* @param name the name of the class | |||||
* @return the resulting class | |||||
* @exception ClassNotFoundException if the class could not be found | |||||
*/ | |||||
protected Class findClass( final String name ) | |||||
throws ClassNotFoundException | |||||
{ | |||||
// Try the parent classloaders first | |||||
for( int i = 0; i < m_parents.length; i++ ) | |||||
{ | |||||
try | |||||
{ | |||||
final ClassLoader parent = m_parents[ i ]; | |||||
return parent.loadClass( name ); | |||||
} | |||||
catch( ClassNotFoundException e ) | |||||
{ | |||||
// Ignore - continue to the next ClassLoader | |||||
} | |||||
} | |||||
// Now this classloader | |||||
return super.findClass( name ); | |||||
} | |||||
/** | |||||
* Finds a resource. | |||||
* | |||||
* @param name the name of the resource | |||||
* @return a <code>URL</code> for the resource, or <code>null</code> | |||||
* if the resource could not be found. | |||||
*/ | |||||
public URL findResource( final String name ) | |||||
{ | |||||
// Try the parent classloaders first | |||||
for( int i = 0; i < m_parents.length; i++ ) | |||||
{ | |||||
final ClassLoader parent = m_parents[ i ]; | |||||
final URL resource = parent.getResource( name ); | |||||
if( resource != null ) | |||||
{ | |||||
return resource; | |||||
} | |||||
} | |||||
// Now this classloader | |||||
return super.findResource( name ); | |||||
} | |||||
/** | |||||
* Returns an Enumeration of URLs representing all of the resources | |||||
* having the specified name. | |||||
* | |||||
* @param name the resource name | |||||
* @throws IOException if an I/O exception occurs | |||||
* @return an <code>Enumeration</code> of <code>URL</code>s | |||||
*/ | |||||
public Enumeration findResources( final String name ) throws IOException | |||||
{ | |||||
// Need to filter out duplicate resources | |||||
final ArrayList urls = new ArrayList(); | |||||
final Set urlSet = new HashSet(); | |||||
// Gather the resources from the parent classloaders | |||||
for( int i = 0; i < m_parents.length; i++ ) | |||||
{ | |||||
final ClassLoader parent = m_parents[ i ]; | |||||
final Enumeration enum = parent.getResources( name ); | |||||
addUrls( enum, urls, urlSet ); | |||||
} | |||||
// Gather the resources from this classloader | |||||
addUrls( super.findResources( name ), urls, urlSet ); | |||||
return Collections.enumeration( urls ); | |||||
} | |||||
/** | |||||
* Adds those URLs not already present. | |||||
*/ | |||||
private void addUrls( final Enumeration enum, | |||||
final List urls, | |||||
final Set urlSet ) | |||||
{ | |||||
while( enum.hasMoreElements() ) | |||||
{ | |||||
final URL url = (URL)enum.nextElement(); | |||||
final String urlStr = url.toExternalForm(); | |||||
if( !urlSet.contains( urlStr ) ) | |||||
{ | |||||
urls.add( url ); | |||||
urlSet.add( urlStr ); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,5 +0,0 @@ | |||||
create-classloader-for-file.error=Could not create a ClassLoader for "{0}". | |||||
create-classloader-for-files.error=Could not create a ClassLoader for {0}. | |||||
unsatisfied.extension.error=Library "{0}" requires unknown extension "{1}" ( version {2}). | |||||
no-file.error=Could not find library "{0}". | |||||
file-is-dir.error=Library "{0}" is a directory. |
@@ -1,567 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
import java.lang.reflect.InvocationTargetException; | |||||
import java.lang.reflect.Method; | |||||
import java.util.ArrayList; | |||||
import org.apache.aut.converter.Converter; | |||||
import org.apache.aut.converter.ConverterException; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.Configurable; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.avalon.framework.logger.LogEnabled; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||||
/** | |||||
* Class used to configure tasks. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @ant.type type="configurer" name="classic" | |||||
*/ | |||||
public class ClassicConfigurer | |||||
extends AbstractLogEnabled | |||||
implements Configurer, Serviceable, LogEnabled | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultConfigurer.class ); | |||||
///Compile time constant to turn on extreme debugging | |||||
private static final boolean DEBUG = false; | |||||
///Converter to use for converting between values | |||||
private Converter m_converter; | |||||
public void service( final ServiceManager serviceManager ) | |||||
throws ServiceException | |||||
{ | |||||
m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||||
} | |||||
/** | |||||
* Configure an object based on a configuration in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* The implementation of this method should only use the methods | |||||
* specified by the supplied class. It is an error for the specified | |||||
* class not to be a base class or interface compatible with specified | |||||
* object. | |||||
* | |||||
* @param object the object | |||||
* @param clazz the Class object to use during configuration | |||||
* @param configuration the configuration | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
public void configureElement( Object object, | |||||
Class clazz, | |||||
Configuration configuration, | |||||
TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
throw new UnsupportedOperationException(); | |||||
} | |||||
/** | |||||
* Configure named attribute of object in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* The implementation of this method should only use the methods | |||||
* specified by the supplied class. It is an error for the specified | |||||
* class not to be a base class or interface compatible with specified | |||||
* object. | |||||
* | |||||
* @param object the object | |||||
* @param clazz the Class object to use during configuration | |||||
* @param name the attribute name | |||||
* @param value the attribute value | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
public void configureAttribute( Object object, | |||||
Class clazz, | |||||
String name, | |||||
String value, | |||||
TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
throw new UnsupportedOperationException(); | |||||
} | |||||
/** | |||||
* Configure a task based on a configuration in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* This one does it by first checking if object implements Configurable | |||||
* and if it does will pass the task the configuration - else it will use | |||||
* mapping rules to map configuration to types | |||||
* | |||||
* @param object the object | |||||
* @param configuration the configuration | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
public void configureElement( final Object object, | |||||
final Configuration configuration, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
if( DEBUG ) | |||||
{ | |||||
final String message = REZ.getString( "configuring-object.notice", object ); | |||||
getLogger().debug( message ); | |||||
} | |||||
if( object instanceof Configurable ) | |||||
{ | |||||
if( DEBUG ) | |||||
{ | |||||
final String message = REZ.getString( "configurable.notice" ); | |||||
getLogger().debug( message ); | |||||
} | |||||
final Configurable configurable = (Configurable)object; | |||||
configurable.configure( configuration ); | |||||
} | |||||
else | |||||
{ | |||||
if( DEBUG ) | |||||
{ | |||||
final String message = REZ.getString( "reflection.notice" ); | |||||
getLogger().debug( message ); | |||||
} | |||||
final String[] attributes = configuration.getAttributeNames(); | |||||
for( int i = 0; i < attributes.length; i++ ) | |||||
{ | |||||
final String name = attributes[ i ]; | |||||
final String value = configuration.getAttribute( name ); | |||||
if( DEBUG ) | |||||
{ | |||||
final String message = REZ.getString( "configure-attribute.notice", | |||||
name, value ); | |||||
getLogger().debug( message ); | |||||
} | |||||
doConfigureAttribute( object, name, value, context ); | |||||
} | |||||
final Configuration[] children = configuration.getChildren(); | |||||
for( int i = 0; i < children.length; i++ ) | |||||
{ | |||||
final Configuration child = children[ i ]; | |||||
if( DEBUG ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "configure-subelement.notice", child.getName() ); | |||||
getLogger().debug( message ); | |||||
} | |||||
doConfigureElement( object, child, context ); | |||||
} | |||||
final String content = configuration.getValue( null ); | |||||
if( null != content ) | |||||
{ | |||||
if( !content.trim().equals( "" ) ) | |||||
{ | |||||
if( DEBUG ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "configure-content.notice", content ); | |||||
getLogger().debug( message ); | |||||
} | |||||
configureContent( object, content, context ); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Configure named attribute of object in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* @param object the object | |||||
* @param name the attribute name | |||||
* @param value the attribute value | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
public void configureAttribute( final Object object, | |||||
final String name, | |||||
final String value, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
doConfigureAttribute( object, name, value, context ); | |||||
} | |||||
/** | |||||
* Try to configure content of an object. | |||||
* | |||||
* @param object the object | |||||
* @param content the content value to be set | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
private void configureContent( final Object object, | |||||
final String content, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
setValue( object, "addContent", content, context ); | |||||
} | |||||
private void doConfigureAttribute( final Object object, | |||||
final String name, | |||||
final String value, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
final String methodName = getMethodNameFor( name ); | |||||
setValue( object, methodName, value, context ); | |||||
} | |||||
private void setValue( final Object object, | |||||
final String methodName, | |||||
final String value, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
// OMFG the rest of this is soooooooooooooooooooooooooooooooo | |||||
// slow. Need to cache results per class etc. | |||||
final Class clazz = object.getClass(); | |||||
final Method[] methods = getMethodsFor( clazz, methodName ); | |||||
if( 0 == methods.length ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "no-attribute-method.error", methodName ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
setValue( object, value, context, methods ); | |||||
} | |||||
private void setValue( final Object object, | |||||
final String value, | |||||
final TaskContext context, | |||||
final Method[] methods ) | |||||
throws ConfigurationException | |||||
{ | |||||
try | |||||
{ | |||||
final Object objectValue = context.resolveValue( value ); | |||||
setValue( object, objectValue, methods, context ); | |||||
} | |||||
catch( final TaskException te ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "bad-property-resolve.error", value ); | |||||
throw new ConfigurationException( message, te ); | |||||
} | |||||
} | |||||
private void setValue( final Object object, | |||||
Object value, | |||||
final Method[] methods, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
final Class sourceClass = value.getClass(); | |||||
final String source = sourceClass.getName(); | |||||
for( int i = 0; i < methods.length; i++ ) | |||||
{ | |||||
if( setValue( object, value, methods[ i ], context ) ) | |||||
{ | |||||
return; | |||||
} | |||||
} | |||||
final String message = | |||||
REZ.getString( "no-can-convert.error", methods[ 0 ].getName(), source ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
private boolean setValue( final Object object, | |||||
final Object originalValue, | |||||
final Method method, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
Class parameterType = method.getParameterTypes()[ 0 ]; | |||||
if( parameterType.isPrimitive() ) | |||||
{ | |||||
parameterType = getComplexTypeFor( parameterType ); | |||||
} | |||||
Object value = originalValue; | |||||
try | |||||
{ | |||||
value = m_converter.convert( parameterType, value, context ); | |||||
} | |||||
catch( final ConverterException ce ) | |||||
{ | |||||
if( DEBUG ) | |||||
{ | |||||
final String message = REZ.getString( "no-converter.error" ); | |||||
getLogger().debug( message, ce ); | |||||
} | |||||
throw new ConfigurationException( ce.getMessage(), ce ); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "bad-convert-for-attribute.error", method.getName() ); | |||||
throw new ConfigurationException( message, e ); | |||||
} | |||||
if( null == value ) | |||||
{ | |||||
return false; | |||||
} | |||||
try | |||||
{ | |||||
method.invoke( object, new Object[]{value} ); | |||||
} | |||||
catch( final IllegalAccessException iae ) | |||||
{ | |||||
//should never happen .... | |||||
final String message = REZ.getString( "illegal-access.error" ); | |||||
throw new ConfigurationException( message, iae ); | |||||
} | |||||
catch( final InvocationTargetException ite ) | |||||
{ | |||||
final String message = REZ.getString( "invoke-target.error", method.getName() ); | |||||
throw new ConfigurationException( message, ite ); | |||||
} | |||||
return true; | |||||
} | |||||
private Class getComplexTypeFor( final Class clazz ) | |||||
{ | |||||
if( String.class == clazz ) | |||||
{ | |||||
return String.class; | |||||
} | |||||
else if( Integer.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Integer.class; | |||||
} | |||||
else if( Long.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Long.class; | |||||
} | |||||
else if( Short.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Short.class; | |||||
} | |||||
else if( Byte.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Byte.class; | |||||
} | |||||
else if( Boolean.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Boolean.class; | |||||
} | |||||
else if( Float.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Float.class; | |||||
} | |||||
else if( Double.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Double.class; | |||||
} | |||||
else | |||||
{ | |||||
final String message = REZ.getString( "no-complex-type.error", clazz.getName() ); | |||||
throw new IllegalArgumentException( message ); | |||||
} | |||||
} | |||||
private Method[] getMethodsFor( final Class clazz, final String methodName ) | |||||
{ | |||||
final Method[] methods = clazz.getMethods(); | |||||
final ArrayList matches = new ArrayList(); | |||||
for( int i = 0; i < methods.length; i++ ) | |||||
{ | |||||
final Method method = methods[ i ]; | |||||
if( methodName.equals( method.getName() ) && | |||||
Method.PUBLIC == ( method.getModifiers() & Method.PUBLIC ) ) | |||||
{ | |||||
if( method.getReturnType().equals( Void.TYPE ) ) | |||||
{ | |||||
final Class[] parameters = method.getParameterTypes(); | |||||
if( 1 == parameters.length ) | |||||
{ | |||||
matches.add( method ); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return (Method[])matches.toArray( new Method[ 0 ] ); | |||||
} | |||||
private Method[] getCreateMethodsFor( final Class clazz, final String methodName ) | |||||
{ | |||||
final Method[] methods = clazz.getMethods(); | |||||
final ArrayList matches = new ArrayList(); | |||||
for( int i = 0; i < methods.length; i++ ) | |||||
{ | |||||
final Method method = methods[ i ]; | |||||
if( methodName.equals( method.getName() ) && | |||||
Method.PUBLIC == ( method.getModifiers() & Method.PUBLIC ) ) | |||||
{ | |||||
final Class returnType = method.getReturnType(); | |||||
if( !returnType.equals( Void.TYPE ) && | |||||
!returnType.isPrimitive() ) | |||||
{ | |||||
final Class[] parameters = method.getParameterTypes(); | |||||
if( 0 == parameters.length ) | |||||
{ | |||||
matches.add( method ); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return (Method[])matches.toArray( new Method[ 0 ] ); | |||||
} | |||||
private String getMethodNameFor( final String attribute ) | |||||
{ | |||||
return "set" + getJavaNameFor( attribute.toLowerCase() ); | |||||
} | |||||
private String getJavaNameFor( final String name ) | |||||
{ | |||||
final StringBuffer sb = new StringBuffer(); | |||||
int index = name.indexOf( '-' ); | |||||
int last = 0; | |||||
while( -1 != index ) | |||||
{ | |||||
final String word = name.substring( last, index ).toLowerCase(); | |||||
sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); | |||||
sb.append( word.substring( 1, word.length() ) ); | |||||
last = index + 1; | |||||
index = name.indexOf( '-', last ); | |||||
} | |||||
index = name.length(); | |||||
final String word = name.substring( last, index ).toLowerCase(); | |||||
sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); | |||||
sb.append( word.substring( 1, word.length() ) ); | |||||
return sb.toString(); | |||||
} | |||||
private void doConfigureElement( final Object object, | |||||
final Configuration configuration, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
final String name = configuration.getName(); | |||||
final String javaName = getJavaNameFor( name ); | |||||
// OMFG the rest of this is soooooooooooooooooooooooooooooooo | |||||
// slow. Need to cache results per class etc. | |||||
final Class clazz = object.getClass(); | |||||
Method[] methods = getMethodsFor( clazz, "add" + javaName ); | |||||
if( 0 != methods.length ) | |||||
{ | |||||
//guess it is first method ???? | |||||
addElement( object, methods[ 0 ], configuration, context ); | |||||
} | |||||
else | |||||
{ | |||||
methods = getCreateMethodsFor( clazz, "create" + javaName ); | |||||
if( 0 == methods.length ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "no-element-method.error", javaName ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
//guess it is first method ???? | |||||
createElement( object, methods[ 0 ], configuration, context ); | |||||
} | |||||
} | |||||
private void createElement( final Object object, | |||||
final Method method, | |||||
final Configuration configuration, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
try | |||||
{ | |||||
final Object created = method.invoke( object, new Object[ 0 ] ); | |||||
doConfigureElement( created, configuration, context ); | |||||
} | |||||
catch( final ConfigurationException ce ) | |||||
{ | |||||
throw ce; | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "subelement-create.error" ); | |||||
throw new ConfigurationException( message, e ); | |||||
} | |||||
} | |||||
private void addElement( final Object object, | |||||
final Method method, | |||||
final Configuration configuration, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
try | |||||
{ | |||||
final Class clazz = method.getParameterTypes()[ 0 ]; | |||||
final Object created = clazz.newInstance(); | |||||
doConfigureElement( created, configuration, context ); | |||||
method.invoke( object, new Object[]{created} ); | |||||
} | |||||
catch( final ConfigurationException ce ) | |||||
{ | |||||
throw ce; | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "subelement-create.error" ); | |||||
throw new ConfigurationException( message, e ); | |||||
} | |||||
} | |||||
} |
@@ -1,57 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
/** | |||||
* A default configuration state implementation. Keeps track of which | |||||
* of the object's properties have been set. | |||||
* | |||||
* @author Adam Murdoch | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class ConfigurationState | |||||
{ | |||||
private final int[] m_propertyCount; | |||||
private final ObjectConfigurer m_configurer; | |||||
private final Object m_object; | |||||
public ConfigurationState( final ObjectConfigurer configurer, | |||||
final Object object, | |||||
final int propertyCount ) | |||||
{ | |||||
m_configurer = configurer; | |||||
m_object = object; | |||||
m_propertyCount = new int[ propertyCount ]; | |||||
} | |||||
/** | |||||
* Returns the configurer being used to configure the object. | |||||
*/ | |||||
public ObjectConfigurer getConfigurer() | |||||
{ | |||||
return m_configurer; | |||||
} | |||||
/** Returns the object being configured. */ | |||||
public Object getObject() | |||||
{ | |||||
return m_object; | |||||
} | |||||
/** Returns a property count. */ | |||||
public int getPropertyCount( final int index ) | |||||
{ | |||||
return m_propertyCount[ index ]; | |||||
} | |||||
/** Increments a property count. */ | |||||
public void incPropertyCount( final int index ) | |||||
{ | |||||
m_propertyCount[ index ]++; | |||||
} | |||||
} |
@@ -1,645 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import org.apache.aut.converter.Converter; | |||||
import org.apache.aut.converter.ConverterException; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.Configurable; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.avalon.framework.logger.LogEnabled; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
import org.apache.myrmidon.framework.DataType; | |||||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
/** | |||||
* Class used to configure tasks. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
* @ant.type type="configurer" name="default" | |||||
*/ | |||||
public class DefaultConfigurer | |||||
extends AbstractLogEnabled | |||||
implements Configurer, Serviceable, LogEnabled | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultConfigurer.class ); | |||||
///Converter to use for converting between values | |||||
private Converter m_converter; | |||||
//TypeManager to use to create types in typed adders | |||||
private TypeManager m_typeManager; | |||||
//RoleManager to use to map from type names -> role shorthand | |||||
private RoleManager m_roleManager; | |||||
///Cached object configurers. This is a map from Class to the | |||||
///ObjectConfigurer for that class. | |||||
private Map m_configurerCache = new HashMap(); | |||||
public void service( final ServiceManager serviceManager ) | |||||
throws ServiceException | |||||
{ | |||||
m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||||
m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||||
m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||||
} | |||||
/** | |||||
* Configure a task based on a configuration in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* This one does it by first checking if object implements Configurable | |||||
* and if it does will pass the task the configuration - else it will use | |||||
* mapping rules to map configuration to types | |||||
* | |||||
* @param object the object | |||||
* @param configuration the configuration | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
public void configureElement( final Object object, | |||||
final Configuration configuration, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
configureElement( object, object.getClass(), configuration, context ); | |||||
} | |||||
public void configureElement( final Object object, | |||||
final Class clazz, | |||||
final Configuration configuration, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
try | |||||
{ | |||||
// Configure the object | |||||
configureObject( object, clazz, configuration, context ); | |||||
} | |||||
catch( final ReportableConfigurationException e ) | |||||
{ | |||||
// Already have a reasonable error message - so rethrow | |||||
throw e.getCause(); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
// Wrap all other errors with general purpose error message | |||||
final String message = REZ.getString( "bad-configure-element.error", | |||||
configuration.getName() ); | |||||
throw new ConfigurationException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Does the work of configuring an object. | |||||
* | |||||
* @throws ReportableConfigurationException On error. This exception | |||||
* indicates that the error has been wrapped with an appropriate | |||||
* error message. | |||||
* @throws Exception On error | |||||
*/ | |||||
private void configureObject( final Object object, | |||||
final Class clazz, | |||||
final Configuration configuration, | |||||
final TaskContext context ) | |||||
throws Exception | |||||
{ | |||||
if( object instanceof Configurable ) | |||||
{ | |||||
// Let the object configure itself | |||||
( (Configurable)object ).configure( configuration ); | |||||
} | |||||
else | |||||
{ | |||||
// Start configuration of the object | |||||
final String elemName = configuration.getName(); | |||||
final ObjectConfigurer configurer = getConfigurer( clazz ); | |||||
final ConfigurationState state = configurer.startConfiguration( object ); | |||||
// Set each of the attributes | |||||
final String[] attributes = configuration.getAttributeNames(); | |||||
for( int i = 0; i < attributes.length; i++ ) | |||||
{ | |||||
final String name = attributes[ i ]; | |||||
try | |||||
{ | |||||
// Set the attribute | |||||
final String value = configuration.getAttribute( name ); | |||||
setAttribute( state, name, value, context ); | |||||
} | |||||
catch( final NoSuchPropertyException nspe ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "no-such-attribute.error", elemName, name ); | |||||
throw new ReportableConfigurationException( message ); | |||||
} | |||||
catch( final Exception ce ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "bad-set-attribute.error", elemName, name ); | |||||
throw new ReportableConfigurationException( message, ce ); | |||||
} | |||||
} | |||||
// Set the text content | |||||
final String content = configuration.getValue( null ); | |||||
if( null != content && content.length() > 0 ) | |||||
{ | |||||
try | |||||
{ | |||||
// Set the content | |||||
setContent( state, content, context ); | |||||
} | |||||
catch( final NoSuchPropertyException nspe ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "no-content.error", elemName ); | |||||
throw new ReportableConfigurationException( message ); | |||||
} | |||||
catch( final Exception ce ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "bad-set-content.error", elemName ); | |||||
throw new ReportableConfigurationException( message, ce ); | |||||
} | |||||
} | |||||
// Create and configure each of the child elements | |||||
final Configuration[] children = configuration.getChildren(); | |||||
for( int i = 0; i < children.length; i++ ) | |||||
{ | |||||
final Configuration childConfig = children[ i ]; | |||||
final String name = childConfig.getName(); | |||||
try | |||||
{ | |||||
configureElement( state, childConfig, context ); | |||||
} | |||||
catch( final NoSuchPropertyException nspe ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "no-such-element.error", elemName, name ); | |||||
throw new ReportableConfigurationException( message ); | |||||
} | |||||
catch( final ReportableConfigurationException ce ) | |||||
{ | |||||
throw ce; | |||||
} | |||||
catch( final Exception ce ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "bad-configure-element.error", name ); | |||||
throw new ReportableConfigurationException( message, ce ); | |||||
} | |||||
} | |||||
// Finish configuring the object | |||||
configurer.finishConfiguration( state ); | |||||
} | |||||
} | |||||
/** | |||||
* Configure named attribute of object in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* @param object the object | |||||
* @param name the attribute name | |||||
* @param value the attribute value | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
public void configureAttribute( final Object object, | |||||
final String name, | |||||
final String value, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
configureAttribute( object, object.getClass(), name, value, context ); | |||||
} | |||||
/** | |||||
* Configure named attribute of object in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* @param object the object | |||||
* @param name the attribute name | |||||
* @param value the attribute value | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
public void configureAttribute( final Object object, | |||||
final Class clazz, | |||||
final String name, | |||||
final String value, | |||||
final TaskContext context ) | |||||
throws ConfigurationException | |||||
{ | |||||
// Locate the configurer for this object | |||||
final ObjectConfigurer configurer = getConfigurer( clazz ); | |||||
// TODO - this ain't right, the validation is going to be screwed up | |||||
final ConfigurationState state = configurer.startConfiguration( object ); | |||||
// Set the attribute value | |||||
try | |||||
{ | |||||
setAttribute( state, name, value, context ); | |||||
} | |||||
catch( final Exception ce ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "bad-set-class-attribute.error", | |||||
name, | |||||
object.getClass().getName() ); | |||||
throw new ConfigurationException( message, ce ); | |||||
} | |||||
// Finish up | |||||
configurer.finishConfiguration( state ); | |||||
} | |||||
/** | |||||
* Sets the text content for the element. | |||||
*/ | |||||
private void setContent( final ConfigurationState state, | |||||
final String content, | |||||
final TaskContext context ) | |||||
throws Exception | |||||
{ | |||||
// Locate the content configurer | |||||
final PropertyConfigurer contentConfigurer = state.getConfigurer().getContentConfigurer(); | |||||
if( contentConfigurer == null ) | |||||
{ | |||||
throw new NoSuchPropertyException(); | |||||
} | |||||
// Set the content | |||||
setValue( contentConfigurer, state, content, context ); | |||||
} | |||||
/** | |||||
* Configures a property from a nested element. | |||||
*/ | |||||
private void configureElement( final ConfigurationState state, | |||||
final Configuration element, | |||||
final TaskContext context ) | |||||
throws Exception | |||||
{ | |||||
final String elementName = element.getName(); | |||||
if( elementName.toLowerCase().endsWith( "-ref" ) ) | |||||
{ | |||||
// A reference | |||||
configureReference( state, element, context ); | |||||
} | |||||
else | |||||
{ | |||||
// An inline object | |||||
configureInline( state, element, context ); | |||||
} | |||||
} | |||||
/** | |||||
* Configure a property from an inline object. | |||||
*/ | |||||
private void configureInline( final ConfigurationState state, | |||||
final Configuration element, | |||||
final TaskContext context ) | |||||
throws Exception | |||||
{ | |||||
final String name = element.getName(); | |||||
// Locate the configurer for the child element | |||||
final PropertyConfigurer childConfigurer = | |||||
getConfigurerFromName( state.getConfigurer(), name, true, true ); | |||||
// Create & configure the child element | |||||
final Object child = | |||||
setupChild( state, element, context, childConfigurer ); | |||||
// Set the child element | |||||
childConfigurer.addValue( state, child ); | |||||
} | |||||
/** | |||||
* Configures a property from a reference. | |||||
*/ | |||||
private void configureReference( final ConfigurationState state, | |||||
final Configuration element, | |||||
final TaskContext context ) | |||||
throws Exception | |||||
{ | |||||
// Extract the id | |||||
final String id = element.getAttribute( "id" ); | |||||
if( 1 != element.getAttributeNames().length || | |||||
0 != element.getChildren().length ) | |||||
{ | |||||
final String message = REZ.getString( "extra-config-for-ref.error" ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
// Set the property | |||||
final String name = element.getName(); | |||||
setReference( state, name, id, context, true ); | |||||
} | |||||
/** | |||||
* Sets a property using a reference. | |||||
*/ | |||||
private void setReference( final ConfigurationState state, | |||||
final String refName, | |||||
final String unresolvedId, | |||||
final TaskContext context, | |||||
final boolean isAdder ) | |||||
throws Exception | |||||
{ | |||||
// Adjust the name | |||||
final String name = refName.substring( 0, refName.length() - 4 ); | |||||
// Locate the configurer for the property | |||||
final PropertyConfigurer configurer = | |||||
getConfigurerFromName( state.getConfigurer(), name, false, isAdder ); | |||||
// Resolve any props in the id | |||||
String id = context.resolveValue( unresolvedId ).toString(); | |||||
// Locate the referenced object | |||||
Object ref = context.getProperty( id ); | |||||
if( null == ref ) | |||||
{ | |||||
final String message = REZ.getString( "unknown-reference.error", id ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
// Convert the object, if necessary | |||||
final Class type = configurer.getType(); | |||||
if( !type.isInstance( ref ) ) | |||||
{ | |||||
try | |||||
{ | |||||
ref = m_converter.convert( type, ref, context ); | |||||
} | |||||
catch( ConverterException e ) | |||||
{ | |||||
final String message = REZ.getString( "mismatch-ref-types.error", id, name ); | |||||
throw new ConfigurationException( message, e ); | |||||
} | |||||
} | |||||
// Set the child element | |||||
configurer.addValue( state, ref ); | |||||
} | |||||
/** | |||||
* Sets an attribute value. | |||||
*/ | |||||
private void setAttribute( final ConfigurationState state, | |||||
final String name, | |||||
final String value, | |||||
final TaskContext context ) | |||||
throws Exception | |||||
{ | |||||
// Set the value | |||||
final PropertyConfigurer property = | |||||
getConfigurerFromName( state.getConfigurer(), name, false, false ); | |||||
setValue( property, state, value, context ); | |||||
} | |||||
/** | |||||
* Sets an attribute value, or an element's text content. | |||||
*/ | |||||
private void setValue( final PropertyConfigurer setter, | |||||
final ConfigurationState state, | |||||
final String value, | |||||
final TaskContext context ) | |||||
throws Exception | |||||
{ | |||||
// Resolve property references in the attribute value | |||||
Object objValue = context.resolveValue( value ); | |||||
// Convert the value to the appropriate type | |||||
final Class type = setter.getType(); | |||||
if( !type.isInstance( objValue ) ) | |||||
{ | |||||
objValue = m_converter.convert( type, objValue, context ); | |||||
} | |||||
// Set the value | |||||
setter.addValue( state, objValue ); | |||||
} | |||||
/** | |||||
* Locates the configurer for a particular class. | |||||
*/ | |||||
private ObjectConfigurer getConfigurer( final Class clazz ) | |||||
throws ConfigurationException | |||||
{ | |||||
ObjectConfigurer configurer = | |||||
(ObjectConfigurer)m_configurerCache.get( clazz ); | |||||
if( null == configurer ) | |||||
{ | |||||
configurer = DefaultObjectConfigurer.getConfigurer( clazz ); | |||||
m_configurerCache.put( clazz, configurer ); | |||||
} | |||||
return configurer; | |||||
} | |||||
/** | |||||
* Creates and configures an inline object. | |||||
*/ | |||||
private Object setupChild( final ConfigurationState state, | |||||
final Configuration element, | |||||
final TaskContext context, | |||||
final PropertyConfigurer childConfigurer ) | |||||
throws Exception | |||||
{ | |||||
final String name = element.getName(); | |||||
final Class type = childConfigurer.getType(); | |||||
if( Configuration.class == type ) | |||||
{ | |||||
//special case where you have add...(Configuration) | |||||
return element; | |||||
} | |||||
// Create an instance | |||||
Object child = null; | |||||
if( childConfigurer == state.getConfigurer().getTypedProperty() ) | |||||
{ | |||||
// Typed property | |||||
child = createTypedObject( name, type ); | |||||
} | |||||
else | |||||
{ | |||||
// Named property | |||||
child = createNamedObject( type ); | |||||
} | |||||
// Configure the object | |||||
final Object object = child; | |||||
configureObject( object, object.getClass(), element, context ); | |||||
// Convert the object, if necessary | |||||
if( !type.isInstance( child ) ) | |||||
{ | |||||
child = m_converter.convert( type, child, context ); | |||||
} | |||||
return child; | |||||
} | |||||
/** | |||||
* Determines the property configurer to use for a particular element | |||||
* or attribute. If the supplied name matches a property of the | |||||
* class being configured, that property configurer is returned. If | |||||
* the supplied name matches the role shorthand for the class' typed | |||||
* property, then the typed property configurer is used. | |||||
* | |||||
* @param configurer The configurer for the class being configured. | |||||
* @param name The attribute/element name. | |||||
*/ | |||||
private PropertyConfigurer getConfigurerFromName( final ObjectConfigurer configurer, | |||||
final String name, | |||||
boolean ignoreRoleName, | |||||
final boolean isAdder ) | |||||
throws Exception | |||||
{ | |||||
// Try a named property | |||||
if( !isAdder ) | |||||
{ | |||||
PropertyConfigurer propertyConfigurer = configurer.getSetter( name ); | |||||
if( propertyConfigurer != null ) | |||||
{ | |||||
return propertyConfigurer; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
PropertyConfigurer propertyConfigurer = configurer.getAdder( name ); | |||||
if( propertyConfigurer != null ) | |||||
{ | |||||
return propertyConfigurer; | |||||
} | |||||
// Try a typed property | |||||
propertyConfigurer = configurer.getTypedProperty(); | |||||
if( propertyConfigurer != null ) | |||||
{ | |||||
if( ignoreRoleName ) | |||||
{ | |||||
return propertyConfigurer; | |||||
} | |||||
else | |||||
{ | |||||
// Check the role name | |||||
final RoleInfo roleInfo = | |||||
m_roleManager.getRoleByType( propertyConfigurer.getType() ); | |||||
if( roleInfo != null && name.equalsIgnoreCase( roleInfo.getShorthand() ) ) | |||||
{ | |||||
return propertyConfigurer; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// Unknown prop | |||||
throw new NoSuchPropertyException(); | |||||
} | |||||
/** | |||||
* Creates an instance for a named property. | |||||
*/ | |||||
private Object createNamedObject( final Class type ) | |||||
throws Exception | |||||
{ | |||||
// Map the expected type to a role. If found, instantiate the default | |||||
// type for that role | |||||
final RoleInfo roleInfo = m_roleManager.getRoleByType( type ); | |||||
if( roleInfo != null ) | |||||
{ | |||||
final String typeName = roleInfo.getDefaultType(); | |||||
if( typeName != null ) | |||||
{ | |||||
// Create the instance | |||||
final TypeFactory factory = m_typeManager.getFactory( roleInfo.getName() ); | |||||
return factory.create( typeName ); | |||||
} | |||||
} | |||||
if( type.isInterface() ) | |||||
{ | |||||
// An interface - don't know how to instantiate it | |||||
final String message = REZ.getString( "instantiate-interface.error", type.getName() ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
// Use the no-args constructor | |||||
return createObject( type ); | |||||
} | |||||
/** | |||||
* Creates an instance of the typed property. | |||||
*/ | |||||
private Object createTypedObject( final String name, | |||||
final Class type ) | |||||
throws Exception | |||||
{ | |||||
// Map the expected type to a role. If found, attempt to create | |||||
// an instance | |||||
final RoleInfo roleInfo = m_roleManager.getRoleByType( type ); | |||||
if( roleInfo != null ) | |||||
{ | |||||
final TypeFactory factory = m_typeManager.getFactory( roleInfo.getName() ); | |||||
if( factory.canCreate( name ) ) | |||||
{ | |||||
return factory.create( name ); | |||||
} | |||||
} | |||||
// Use the generic 'data-type' role. | |||||
final TypeFactory factory = m_typeManager.getFactory( DataType.ROLE ); | |||||
if( !factory.canCreate( name ) ) | |||||
{ | |||||
throw new NoSuchPropertyException(); | |||||
} | |||||
return factory.create( name ); | |||||
} | |||||
/** | |||||
* Utility method to instantiate an instance of the specified class. | |||||
*/ | |||||
private Object createObject( final Class type ) | |||||
throws Exception | |||||
{ | |||||
try | |||||
{ | |||||
return type.newInstance(); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "create-object.error", | |||||
type.getName() ); | |||||
throw new ConfigurationException( message, e ); | |||||
} | |||||
} | |||||
} |
@@ -1,395 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
import java.lang.reflect.Method; | |||||
import java.lang.reflect.Modifier; | |||||
import java.util.ArrayList; | |||||
import java.util.Collection; | |||||
import java.util.HashMap; | |||||
import java.util.Iterator; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
/** | |||||
* An object configurer which uses reflection to determine the properties | |||||
* of a class. | |||||
* | |||||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class DefaultObjectConfigurer | |||||
implements ObjectConfigurer | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultObjectConfigurer.class ); | |||||
private final Class m_class; | |||||
/** | |||||
* Adder property configurers. (For XML elements) | |||||
*/ | |||||
private final HashMap m_adders = new HashMap(); | |||||
/** | |||||
* Setter property configurers. (For XML attributes) | |||||
*/ | |||||
private final HashMap m_setters = new HashMap(); | |||||
/** | |||||
* The typed property configurer. | |||||
*/ | |||||
private PropertyConfigurer m_typedPropertyConfigurer; | |||||
/** | |||||
* Content configurer. | |||||
*/ | |||||
private PropertyConfigurer m_contentConfigurer; | |||||
/** | |||||
* Total number of properties. | |||||
*/ | |||||
private int m_propCount; | |||||
/** | |||||
* Creates an object configurer for a particular class. The newly | |||||
* created configurer will not handle any attributes, elements, or content. | |||||
* Use the various <code>enable</code> methods to enable handling of these. | |||||
*/ | |||||
private DefaultObjectConfigurer( final Class classInfo ) | |||||
{ | |||||
m_class = classInfo; | |||||
} | |||||
/** | |||||
* Enables all properties and content handling. | |||||
*/ | |||||
private void enableAll() | |||||
throws ConfigurationException | |||||
{ | |||||
enableSetters(); | |||||
enableAdders(); | |||||
enableTypedAdder(); | |||||
enableContent(); | |||||
} | |||||
/** | |||||
* Enables all setters. | |||||
*/ | |||||
private void enableSetters() | |||||
throws ConfigurationException | |||||
{ | |||||
// Locate all the setter methods | |||||
final Collection methods = findMethods( "set", false ); | |||||
// Create a configurer for each setter | |||||
final Iterator iterator = methods.iterator(); | |||||
while( iterator.hasNext() ) | |||||
{ | |||||
final Method method = (Method)iterator.next(); | |||||
final Class type = method.getParameterTypes()[ 0 ]; | |||||
final String propName = extractName( 3, method.getName() ); | |||||
final DefaultPropertyConfigurer setter = | |||||
new DefaultPropertyConfigurer( getPropertyCount(), | |||||
type, | |||||
method, | |||||
1 ); | |||||
m_setters.put( propName, setter ); | |||||
} | |||||
} | |||||
/** | |||||
* Enables all adders. | |||||
*/ | |||||
private void enableAdders() | |||||
throws ConfigurationException | |||||
{ | |||||
// Locate all the adder methods | |||||
final Collection methods = findMethods( "add", false ); | |||||
final Iterator iterator = methods.iterator(); | |||||
while( iterator.hasNext() ) | |||||
{ | |||||
final Method method = (Method)iterator.next(); | |||||
final String methodName = method.getName(); | |||||
// Skip the text content method | |||||
if( methodName.equals( "addContent" ) ) | |||||
{ | |||||
continue; | |||||
} | |||||
final Class type = method.getParameterTypes()[ 0 ]; | |||||
final String propName = extractName( 3, methodName ); | |||||
final DefaultPropertyConfigurer configurer = | |||||
new DefaultPropertyConfigurer( getPropertyCount(), | |||||
type, | |||||
method, | |||||
Integer.MAX_VALUE ); | |||||
m_adders.put( propName, configurer ); | |||||
} | |||||
} | |||||
/** | |||||
* Enables the typed adder. | |||||
*/ | |||||
private void enableTypedAdder() | |||||
throws ConfigurationException | |||||
{ | |||||
final Collection methods = findMethods( "add", true ); | |||||
if( methods.size() == 0 ) | |||||
{ | |||||
return; | |||||
} | |||||
final Method method = (Method)methods.iterator().next(); | |||||
final Class type = method.getParameterTypes()[ 0 ]; | |||||
// TODO - this isn't necessary | |||||
if( !type.isInterface() ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "typed-adder-non-interface.error", | |||||
m_class.getName(), | |||||
type.getName() ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
m_typedPropertyConfigurer | |||||
= new DefaultPropertyConfigurer( getPropertyCount(), | |||||
type, | |||||
method, | |||||
Integer.MAX_VALUE ); | |||||
} | |||||
/** | |||||
* Enables text content. | |||||
*/ | |||||
private void enableContent() | |||||
throws ConfigurationException | |||||
{ | |||||
// Locate the 'addContent' methods, which return void, and take | |||||
// a single parameter. | |||||
final Collection methods = findMethods( "addContent", true ); | |||||
if( methods.size() == 0 ) | |||||
{ | |||||
return; | |||||
} | |||||
final Method method = (Method)methods.iterator().next(); | |||||
final Class type = method.getParameterTypes()[ 0 ]; | |||||
m_contentConfigurer = new DefaultPropertyConfigurer( getPropertyCount(), | |||||
type, | |||||
method, | |||||
1 ); | |||||
} | |||||
/** | |||||
* Locate all methods whose name starts with a particular | |||||
* prefix, and which are non-static, return void, and take a single | |||||
* non-array parameter. If there are more than one matching methods of | |||||
* a given name, the method that takes a String parameter (if any) is | |||||
* ignored. If after that there are more than one matching methods of | |||||
* a given name, an exception is thrown. | |||||
* | |||||
* @return Map from property name -> Method object for that property. | |||||
*/ | |||||
private Collection findMethods( final String prefix, | |||||
final boolean exactMatch ) | |||||
throws ConfigurationException | |||||
{ | |||||
final Map methods = new HashMap(); | |||||
final List allMethods = findMethodsWithPrefix( prefix, exactMatch ); | |||||
final Iterator iterator = allMethods.iterator(); | |||||
while( iterator.hasNext() ) | |||||
{ | |||||
final Method method = (Method)iterator.next(); | |||||
final String methodName = method.getName(); | |||||
if( Void.TYPE != method.getReturnType() || | |||||
1 != method.getParameterTypes().length || | |||||
method.getParameterTypes()[ 0 ].isArray() ) | |||||
{ | |||||
continue; | |||||
} | |||||
// Extract property name | |||||
final Class type = method.getParameterTypes()[ 0 ]; | |||||
// Add to the adders map | |||||
if( methods.containsKey( methodName ) ) | |||||
{ | |||||
final Method candidate = (Method)methods.get( methodName ); | |||||
final Class currentType = candidate.getParameterTypes()[ 0 ]; | |||||
// Ditch the string version, if any | |||||
if( currentType != String.class && type == String.class ) | |||||
{ | |||||
// New type is string, and current type is not. Ignore | |||||
// the new method | |||||
continue; | |||||
} | |||||
else if( currentType != String.class || type == String.class ) | |||||
{ | |||||
// Both are string (which would be odd), or both are not string | |||||
final String message = | |||||
REZ.getString( "multiple-methods-for-element.error", | |||||
m_class.getName(), | |||||
methodName ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
// Else, current type is string, and new type is not, so | |||||
// continue below, and replace the current method | |||||
} | |||||
methods.put( methodName, method ); | |||||
} | |||||
return methods.values(); | |||||
} | |||||
private int getPropertyCount() | |||||
{ | |||||
return m_propCount++; | |||||
} | |||||
/** | |||||
* Locates the configurer for a particular class. | |||||
*/ | |||||
public static ObjectConfigurer getConfigurer( final Class classInfo ) | |||||
throws ConfigurationException | |||||
{ | |||||
final DefaultObjectConfigurer configurer = new DefaultObjectConfigurer( classInfo ); | |||||
configurer.enableAll(); | |||||
return configurer; | |||||
} | |||||
/** | |||||
* Starts the configuration of an object. | |||||
*/ | |||||
public ConfigurationState startConfiguration( Object object ) | |||||
throws ConfigurationException | |||||
{ | |||||
return new ConfigurationState( this, object, getPropertyCount() ); | |||||
} | |||||
/** | |||||
* Finishes the configuration of an object, performing any final | |||||
* validation and type conversion. | |||||
*/ | |||||
public Object finishConfiguration( final ConfigurationState state ) | |||||
throws ConfigurationException | |||||
{ | |||||
// Make sure there are no pending created objects | |||||
final ConfigurationState defState = (ConfigurationState)state; | |||||
return defState.getObject(); | |||||
} | |||||
/** | |||||
* Returns a configurer for an element of this class. | |||||
*/ | |||||
public PropertyConfigurer getAdder( final String name ) | |||||
{ | |||||
return (PropertyConfigurer)m_adders.get( name ); | |||||
} | |||||
/** | |||||
* Returns a configurer for an element of this class. | |||||
*/ | |||||
public PropertyConfigurer getSetter( final String name ) | |||||
{ | |||||
return (PropertyConfigurer)m_setters.get( name ); | |||||
} | |||||
/** | |||||
* Returns a configurer for the typed property of this class. | |||||
*/ | |||||
public PropertyConfigurer getTypedProperty() | |||||
{ | |||||
return m_typedPropertyConfigurer; | |||||
} | |||||
/** | |||||
* Returns a configurer for the content of this class. | |||||
*/ | |||||
public PropertyConfigurer getContentConfigurer() | |||||
{ | |||||
return m_contentConfigurer; | |||||
} | |||||
/** | |||||
* Extracts a property name from a Java method name. | |||||
* | |||||
* <p>Removes the prefix, inserts '-' before each uppercase character | |||||
* (except the first), then converts all to lowercase. | |||||
*/ | |||||
private String extractName( final int prefixLen, final String methodName ) | |||||
{ | |||||
final StringBuffer sb = new StringBuffer( methodName ); | |||||
sb.delete( 0, prefixLen ); | |||||
//Contains the index that we are up to in string buffer. | |||||
//May not be equal to i as length of string buffer may change | |||||
int index = 0; | |||||
final int size = sb.length(); | |||||
for( int i = 0; i < size; i++ ) | |||||
{ | |||||
char ch = sb.charAt( index ); | |||||
if( Character.isUpperCase( ch ) ) | |||||
{ | |||||
if( index > 0 ) | |||||
{ | |||||
sb.insert( index, '-' ); | |||||
index++; | |||||
} | |||||
sb.setCharAt( index, Character.toLowerCase( ch ) ); | |||||
} | |||||
index++; | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
/** | |||||
* Locates all non-static methods whose name starts with a particular | |||||
* prefix. | |||||
*/ | |||||
private List findMethodsWithPrefix( final String prefix, | |||||
final boolean exactMatch ) | |||||
{ | |||||
final ArrayList matches = new ArrayList(); | |||||
final int prefixLen = prefix.length(); | |||||
final Method[] methods = m_class.getMethods(); | |||||
for( int i = 0; i < methods.length; i++ ) | |||||
{ | |||||
final Method method = methods[ i ]; | |||||
final String methodName = method.getName(); | |||||
if( Modifier.isStatic( method.getModifiers() ) ) | |||||
{ | |||||
continue; | |||||
} | |||||
if( methodName.length() < prefixLen || !methodName.startsWith( prefix ) ) | |||||
{ | |||||
continue; | |||||
} | |||||
if( exactMatch && methodName.length() != prefixLen ) | |||||
{ | |||||
continue; | |||||
} | |||||
matches.add( method ); | |||||
} | |||||
return matches; | |||||
} | |||||
} |
@@ -1,139 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
import java.lang.reflect.InvocationTargetException; | |||||
import java.lang.reflect.Method; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
/** | |||||
* The default property configurer implementation, which uses reflection to | |||||
* create and set property values. | |||||
* | |||||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class DefaultPropertyConfigurer | |||||
implements PropertyConfigurer | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultPropertyConfigurer.class ); | |||||
private final int m_propertyIndex; | |||||
private final Class m_type; | |||||
private final Method m_method; | |||||
private final int m_maxCount; | |||||
public DefaultPropertyConfigurer( final int propIndex, | |||||
final Class type, | |||||
final Method method, | |||||
final int maxCount ) | |||||
{ | |||||
m_propertyIndex = propIndex; | |||||
if( type.isPrimitive() ) | |||||
{ | |||||
m_type = getComplexTypeFor( type ); | |||||
} | |||||
else | |||||
{ | |||||
m_type = type; | |||||
} | |||||
m_method = method; | |||||
m_maxCount = maxCount; | |||||
if( null == m_method ) | |||||
{ | |||||
throw new NullPointerException( "method" ); | |||||
} | |||||
} | |||||
/** | |||||
* Returns the type of the element. | |||||
*/ | |||||
public Class getType() | |||||
{ | |||||
return m_type; | |||||
} | |||||
/** | |||||
* Adds a value for this property, to an object. | |||||
*/ | |||||
public void addValue( final ConfigurationState state, final Object value ) | |||||
throws ConfigurationException | |||||
{ | |||||
final ConfigurationState defState = (ConfigurationState)state; | |||||
// Check the property count | |||||
if( defState.getPropertyCount( m_propertyIndex ) >= m_maxCount ) | |||||
{ | |||||
final String message = REZ.getString( "too-many-values.error" ); | |||||
throw new ConfigurationException( message ); | |||||
} | |||||
defState.incPropertyCount( m_propertyIndex ); | |||||
try | |||||
{ | |||||
// Add the value | |||||
m_method.invoke( defState.getObject(), new Object[]{value} ); | |||||
} | |||||
catch( final InvocationTargetException ite ) | |||||
{ | |||||
final Throwable cause = ite.getTargetException(); | |||||
throw new ConfigurationException( cause.getMessage(), cause ); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
throw new ConfigurationException( e.getMessage(), e ); | |||||
} | |||||
} | |||||
/** | |||||
* Determines the complex type for a prmitive type. | |||||
*/ | |||||
private Class getComplexTypeFor( final Class clazz ) | |||||
{ | |||||
if( String.class == clazz ) | |||||
{ | |||||
return String.class; | |||||
} | |||||
else if( Integer.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Integer.class; | |||||
} | |||||
else if( Long.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Long.class; | |||||
} | |||||
else if( Short.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Short.class; | |||||
} | |||||
else if( Byte.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Byte.class; | |||||
} | |||||
else if( Boolean.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Boolean.class; | |||||
} | |||||
else if( Float.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Float.class; | |||||
} | |||||
else if( Double.TYPE.equals( clazz ) ) | |||||
{ | |||||
return Double.class; | |||||
} | |||||
else | |||||
{ | |||||
final String message = REZ.getString( "no-complex-type.error", clazz.getName() ); | |||||
throw new IllegalArgumentException( message ); | |||||
} | |||||
} | |||||
} |
@@ -1,19 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
/** | |||||
* A marker exception that is thrown when an unknown property is encountered. | |||||
* | |||||
* @author Adam Murdoch | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class NoSuchPropertyException | |||||
extends Exception | |||||
{ | |||||
} |
@@ -1,75 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
/** | |||||
* Configures objects of a particular class. | |||||
* | |||||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
interface ObjectConfigurer | |||||
{ | |||||
/** | |||||
* Starts the configuration of an object. | |||||
* | |||||
* @param object The object about to be configured. | |||||
* @return The state object, used to track type-specific state during | |||||
* configuration. | |||||
* @throws ConfigurationException On error starting the configuration. | |||||
*/ | |||||
ConfigurationState startConfiguration( Object object ) | |||||
throws ConfigurationException; | |||||
/** | |||||
* Finishes the configuration of an object, performing any final | |||||
* validation and type conversion. | |||||
* | |||||
* @param state The state object. | |||||
* @return The configured object. | |||||
* @throws ConfigurationException On error finishing the configurtion. | |||||
*/ | |||||
Object finishConfiguration( ConfigurationState state ) | |||||
throws ConfigurationException; | |||||
/** | |||||
* Returns a configurer for a atribute property of this class. | |||||
* | |||||
* @param name The attribute name. | |||||
* @return A configurer for the property, or null if the property is not | |||||
* valid for this class. | |||||
*/ | |||||
PropertyConfigurer getSetter( String name ); | |||||
/** | |||||
* Returns a configurer for a element property of this class. | |||||
* | |||||
* @param name The element name. | |||||
* @return A configurer for the property, or null if the property is not | |||||
* valid for this class. | |||||
*/ | |||||
PropertyConfigurer getAdder( String name ); | |||||
/** | |||||
* Returns a configurer for the text content of this class. | |||||
* | |||||
* @return A configurer for the text content, or null if the class does not | |||||
* support text content. | |||||
*/ | |||||
PropertyConfigurer getContentConfigurer(); | |||||
/** | |||||
* Returns a configurer for the typed property of this class. | |||||
* | |||||
* @return A configurer for the typed property, or null if the class | |||||
* does not have a typed property. | |||||
*/ | |||||
PropertyConfigurer getTypedProperty(); | |||||
} |
@@ -1,36 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
/** | |||||
* Configures a property of an object. | |||||
* TODO - axe createValue(). | |||||
* | |||||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
interface PropertyConfigurer | |||||
{ | |||||
/** | |||||
* Returns the type of this property. | |||||
*/ | |||||
Class getType(); | |||||
/** | |||||
* Adds a value for this property, to an object. | |||||
* | |||||
* @param state The state object, representing the object being configured. | |||||
* @param value The property value. This must be assignable to the type | |||||
* returned by {@link #getType}. | |||||
* @throws ConfigurationException If the property cannot be set. | |||||
*/ | |||||
void addValue( ConfigurationState state, Object value ) | |||||
throws ConfigurationException; | |||||
} |
@@ -1,39 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.configurer; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
/** | |||||
* A marker exception. | |||||
* | |||||
* TODO - this should extend ConfigurationException, except it is final. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class ReportableConfigurationException | |||||
extends Exception | |||||
{ | |||||
private ConfigurationException m_cause; | |||||
public ReportableConfigurationException( String s ) | |||||
{ | |||||
m_cause = new ConfigurationException( s ); | |||||
} | |||||
public ReportableConfigurationException( String s, Throwable throwable ) | |||||
{ | |||||
m_cause = new ConfigurationException( s, throwable ); | |||||
} | |||||
public ConfigurationException getCause() | |||||
{ | |||||
return m_cause; | |||||
} | |||||
} |
@@ -1,17 +0,0 @@ | |||||
create-object.error=Could not create an object of class {0}. | |||||
extra-config-for-ref.error=A reference element can only include an "id" attribute. | |||||
mismatch-ref-types.error=Could not convert reference "{0}" to the type expected for property "{1}". | |||||
incompatible-element-types.error=Incompatible creator and adder/setter methods found in class {0} for property "{1}". | |||||
multiple-methods-for-element.error=Multiple non-String {1}() methods found in class {0}. | |||||
too-many-values.error=Too many values for this property. | |||||
no-complex-type.error=Can not get complex type for non-primitive type {0}. | |||||
no-such-attribute.error=Element <{0}> does not support attribute "{1}". | |||||
bad-set-attribute.error=Could not set attribute "{1}" for element <{0}>. | |||||
bad-set-class-attribute.error=Could not set attribute "{0}" for object of class {1}. | |||||
no-such-element.error=Element <{0}> does not support nested <{1}> elements. | |||||
no-content.error=Element <{0} does not support text content. | |||||
bad-set-content.error=Could not set text content for element <{0}>. | |||||
typed-adder-non-interface.error=The typed adder for class "{0}" must have a single parameter that is an interface rather than {1} which defines a class. | |||||
create-typed-object.error=Could not create an object of type "{0}" of class {1}. | |||||
unknown-reference.error=Could not find referenced object "{0}". | |||||
bad-configure-element.error=Could not configure element <{0}>. |
@@ -1,70 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.converter; | |||||
import org.apache.aut.converter.Converter; | |||||
import org.apache.aut.converter.AbstractMasterConverter; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
/** | |||||
* Converter engine to handle converting between types. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultMasterConverter | |||||
extends AbstractMasterConverter | |||||
implements ConverterRegistry, Serviceable | |||||
{ | |||||
private TypeManager m_typeManager; | |||||
/** | |||||
* Retrieve relevent services needed to deploy. | |||||
* | |||||
* @param serviceManager the ServiceManager | |||||
* @exception ServiceException if an error occurs | |||||
*/ | |||||
public void service( final ServiceManager serviceManager ) | |||||
throws ServiceException | |||||
{ | |||||
m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||||
} | |||||
/** | |||||
* Register a converter | |||||
* | |||||
* @param className the className of converter | |||||
* @param source the source classname | |||||
* @param destination the destination classname | |||||
*/ | |||||
public void registerConverter( final String className, | |||||
final String source, | |||||
final String destination ) | |||||
{ | |||||
super.registerConverter( className, source, destination ); | |||||
} | |||||
/** | |||||
* Create an instance of converter with specified name. | |||||
* | |||||
* @param name the name of converter | |||||
* @return the created converter instance | |||||
* @throws Exception if converter can not be created. | |||||
*/ | |||||
protected Converter createConverter( final String name ) | |||||
throws Exception | |||||
{ | |||||
final TypeFactory factory = m_typeManager.getFactory( Converter.ROLE ); | |||||
return (Converter)factory.create( name ); | |||||
} | |||||
} |
@@ -1,289 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import java.io.File; | |||||
import java.net.URL; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import org.apache.aut.converter.Converter; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||||
import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||||
import org.apache.myrmidon.interfaces.deployer.ConverterDefinition; | |||||
import org.apache.myrmidon.interfaces.deployer.Deployer; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
/** | |||||
* This class deploys roles, types and services from a typelib. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultDeployer | |||||
extends AbstractLogEnabled | |||||
implements Deployer, Serviceable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultDeployer.class ); | |||||
// The components used to deploy | |||||
private ConverterRegistry m_converterRegistry; | |||||
private TypeManager m_typeManager; | |||||
private RoleManager m_roleManager; | |||||
private ClassLoaderManager m_classLoaderManager; | |||||
/** Map from ClassLoader to the deployer for that class loader. */ | |||||
private final Map m_classLoaderDeployers = new HashMap(); | |||||
/** | |||||
* Retrieve relevent services needed to deploy. | |||||
* | |||||
* @param serviceManager the ServiceManager | |||||
* @exception ServiceException if an error occurs | |||||
*/ | |||||
public void service( final ServiceManager serviceManager ) | |||||
throws ServiceException | |||||
{ | |||||
m_converterRegistry = (ConverterRegistry)serviceManager.lookup( ConverterRegistry.ROLE ); | |||||
m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||||
m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||||
m_classLoaderManager = (ClassLoaderManager)serviceManager.lookup( ClassLoaderManager.ROLE ); | |||||
} | |||||
/** | |||||
* Creates a child deployer. | |||||
*/ | |||||
public Deployer createChildDeployer( final ServiceManager componentManager ) | |||||
throws ServiceException | |||||
{ | |||||
final DefaultDeployer child = new DefaultDeployer(); | |||||
setupLogger( child ); | |||||
child.service( componentManager ); | |||||
return child; | |||||
} | |||||
/** | |||||
* Returns the deployer for a ClassLoader, creating the deployer if | |||||
* necessary. | |||||
*/ | |||||
public TypeDeployer createDeployer( final ClassLoader loader ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
return createDeployment( loader, null ); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "deploy-from-classloader.error", loader ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Returns the deployer for a type library, creating the deployer if | |||||
* necessary. | |||||
*/ | |||||
public TypeDeployer createDeployer( final File file ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
final ClassLoader classLoader = m_classLoaderManager.getClassLoader( file ); | |||||
return createDeployment( classLoader, file.toURL() ); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "deploy-from-file.error", file ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Creates a deployer for a ClassLoader. | |||||
*/ | |||||
private Deployment createDeployment( final ClassLoader loader, | |||||
final URL jarUrl ) | |||||
throws Exception | |||||
{ | |||||
// Locate cached deployer, creating it if necessary | |||||
Deployment deployment = (Deployment)m_classLoaderDeployers.get( loader ); | |||||
if( deployment == null ) | |||||
{ | |||||
deployment = new Deployment( this, loader ); | |||||
setupLogger( deployment ); | |||||
deployment.loadDescriptors( jarUrl ); | |||||
m_classLoaderDeployers.put( loader, deployment ); | |||||
} | |||||
return deployment; | |||||
} | |||||
/** | |||||
* Deploys a service. | |||||
*/ | |||||
public void deployService( final Deployment deployment, | |||||
final ServiceDefinition definition ) | |||||
throws Exception | |||||
{ | |||||
final String roleShorthand = definition.getRoleShorthand(); | |||||
final String roleName = getRole( roleShorthand ).getName(); | |||||
final String factoryClassName = definition.getFactoryClass(); | |||||
handleType( deployment, ServiceFactory.ROLE, roleName, factoryClassName ); | |||||
} | |||||
/** | |||||
* Handles a type definition. | |||||
*/ | |||||
public void deployType( final Deployment deployment, | |||||
final TypeDefinition typeDef ) | |||||
throws Exception | |||||
{ | |||||
final String typeName = typeDef.getName(); | |||||
final String roleShorthand = typeDef.getRole(); | |||||
final String className = typeDef.getClassname(); | |||||
if( null == className ) | |||||
{ | |||||
final String message = REZ.getString( "typedef.no-classname.error" ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
if( typeDef instanceof ConverterDefinition ) | |||||
{ | |||||
// Validate the definition | |||||
final ConverterDefinition converterDef = (ConverterDefinition)typeDef; | |||||
final String srcClass = converterDef.getSourceType(); | |||||
final String destClass = converterDef.getDestinationType(); | |||||
if( null == srcClass ) | |||||
{ | |||||
final String message = REZ.getString( "converterdef.no-source.error" ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
if( null == destClass ) | |||||
{ | |||||
final String message = REZ.getString( "converterdef.no-destination.error" ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
// Deploy the converter | |||||
handleConverter( deployment, className, srcClass, destClass ); | |||||
} | |||||
else | |||||
{ | |||||
// Validate the definition | |||||
if( null == roleShorthand ) | |||||
{ | |||||
final String message = REZ.getString( "typedef.no-role.error" ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
else if( null == typeName ) | |||||
{ | |||||
final String message = REZ.getString( "typedef.no-name.error" ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
// Deploy general-purpose type | |||||
final String roleName = getRole( roleShorthand ).getName(); | |||||
handleType( deployment, roleName, typeName, className ); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "register-type.notice", roleShorthand, typeName ); | |||||
getLogger().debug( message ); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Handles a type definition. | |||||
*/ | |||||
private void handleType( final Deployment deployment, | |||||
final String roleName, | |||||
final String typeName, | |||||
final String className ) | |||||
throws Exception | |||||
{ | |||||
// TODO - detect duplicates | |||||
final DefaultTypeFactory factory = deployment.getFactory( roleName ); | |||||
factory.addNameClassMapping( typeName, className ); | |||||
m_typeManager.registerType( roleName, typeName, factory ); | |||||
} | |||||
/** | |||||
* Handles a converter definition. | |||||
*/ | |||||
private void handleConverter( final Deployment deployment, | |||||
final String className, | |||||
final String source, | |||||
final String destination ) | |||||
throws Exception | |||||
{ | |||||
m_converterRegistry.registerConverter( className, source, destination ); | |||||
final DefaultTypeFactory factory = deployment.getFactory( Converter.ROLE ); | |||||
factory.addNameClassMapping( className, className ); | |||||
m_typeManager.registerType( Converter.ROLE, className, factory ); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "register-converter.notice", source, destination ); | |||||
getLogger().debug( message ); | |||||
} | |||||
} | |||||
/** | |||||
* Handles a role definition. | |||||
*/ | |||||
public void deployRole( final Deployment deployment, | |||||
final RoleDefinition roleDef ) | |||||
throws Exception | |||||
{ | |||||
final String name = roleDef.getShortHand(); | |||||
final String role = roleDef.getRoleName(); | |||||
final Class type = deployment.getClassLoader().loadClass( role ); | |||||
final RoleInfo roleInfo = new RoleInfo( role, name, type, null ); | |||||
m_roleManager.addRole( roleInfo ); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String debugMessage = REZ.getString( "register-role.notice", role, name ); | |||||
getLogger().debug( debugMessage ); | |||||
} | |||||
} | |||||
/** | |||||
* Locates a role, from its shorthand. | |||||
*/ | |||||
private RoleInfo getRole( final String roleShorthand ) | |||||
throws DeploymentException | |||||
{ | |||||
final RoleInfo roleInfo = m_roleManager.getRoleByShorthandName( roleShorthand ); | |||||
if( null == roleInfo ) | |||||
{ | |||||
final String message = REZ.getString( "unknown-role4name.error", roleShorthand ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
return roleInfo; | |||||
} | |||||
} |
@@ -1,363 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import java.io.FileNotFoundException; | |||||
import java.net.URL; | |||||
import java.util.ArrayList; | |||||
import java.util.Enumeration; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import javax.xml.parsers.SAXParser; | |||||
import javax.xml.parsers.SAXParserFactory; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||||
import org.xml.sax.XMLReader; | |||||
/** | |||||
* This class deploys type libraries from a ClassLoader into a registry. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class Deployment | |||||
extends AbstractLogEnabled | |||||
implements TypeDeployer | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( Deployment.class ); | |||||
private static final String TYPE_DESCRIPTOR_NAME = "META-INF/ant-descriptor.xml"; | |||||
private static final String ROLE_DESCRIPTOR_NAME = "META-INF/ant-roles.xml"; | |||||
private static final String SERVICE_DESCRIPTOR_NAME = "META-INF/ant-services.xml"; | |||||
private ClassLoader m_classLoader; | |||||
private DefaultDeployer m_deployer; | |||||
private TypeDescriptor[] m_descriptors; | |||||
private ServiceDescriptor[] m_services; | |||||
// TODO - create and configure these in DefaultDeployer | |||||
private DescriptorBuilder m_roleBuilder = new RoleDescriptorBuilder(); | |||||
private DescriptorBuilder m_typeBuilder = new TypeDescriptorBuilder(); | |||||
private DescriptorBuilder m_serviceBuilder = new ServiceDescriptorBuilder(); | |||||
/** Map from role Class -> DefaultTypeFactory for that role. */ | |||||
private Map m_factories = new HashMap(); | |||||
public Deployment( final DefaultDeployer deployer, final ClassLoader classLoader ) | |||||
{ | |||||
m_deployer = deployer; | |||||
m_classLoader = classLoader; | |||||
} | |||||
/** | |||||
* Load the descriptors. Deploys all roles, then loads the descriptors | |||||
* for, but does not deploy, all the types. | |||||
* | |||||
* @param jarUrl The URL for the typelib, used to locate the descriptors. | |||||
* If null, the resources from the classloader are used. | |||||
*/ | |||||
public void loadDescriptors( final URL jarUrl ) | |||||
throws Exception | |||||
{ | |||||
// Create a SAX parser to assemble the descriptors into Configuration | |||||
// objects | |||||
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||||
final SAXParser saxParser = saxParserFactory.newSAXParser(); | |||||
final XMLReader parser = saxParser.getXMLReader(); | |||||
//parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false ); | |||||
final SAXConfigurationHandler handler = new SAXConfigurationHandler(); | |||||
parser.setContentHandler( handler ); | |||||
parser.setErrorHandler( handler ); | |||||
// Build the role descriptors | |||||
final ArrayList roleUrls = locateResources( ROLE_DESCRIPTOR_NAME, jarUrl ); | |||||
final ArrayList roleDescriptors = | |||||
buildDescriptors( roleUrls, m_roleBuilder, parser, handler ); | |||||
// Deploy the roles | |||||
// TODO - need to defer this | |||||
final int roleCount = roleDescriptors.size(); | |||||
for( int i = 0; i < roleCount; i++ ) | |||||
{ | |||||
final RoleDescriptor descriptor = (RoleDescriptor)roleDescriptors.get( i ); | |||||
deployRoles( descriptor ); | |||||
} | |||||
// Build the type descriptors | |||||
final ArrayList typeUrls = locateResources( TYPE_DESCRIPTOR_NAME, jarUrl ); | |||||
final ArrayList typeDescriptors = | |||||
buildDescriptors( typeUrls, m_typeBuilder, parser, handler ); | |||||
m_descriptors = (TypeDescriptor[])typeDescriptors.toArray | |||||
( new TypeDescriptor[ typeDescriptors.size() ] ); | |||||
// Build the service descriptors | |||||
final ArrayList serviceUrls = locateResources( SERVICE_DESCRIPTOR_NAME, jarUrl ); | |||||
final ArrayList serviceDescriptors = | |||||
buildDescriptors( serviceUrls, m_serviceBuilder, parser, handler ); | |||||
m_services = (ServiceDescriptor[])serviceDescriptors.toArray | |||||
( new ServiceDescriptor[ serviceDescriptors.size() ] ); | |||||
} | |||||
/** | |||||
* Returns the type factory for a role. | |||||
*/ | |||||
public DefaultTypeFactory getFactory( final String roleName ) | |||||
{ | |||||
DefaultTypeFactory factory = (DefaultTypeFactory)m_factories.get( roleName ); | |||||
if( null == factory ) | |||||
{ | |||||
factory = new DefaultTypeFactory( m_classLoader ); | |||||
m_factories.put( roleName, factory ); | |||||
} | |||||
return factory; | |||||
} | |||||
/** | |||||
* Returns the classloader for this deployment. | |||||
*/ | |||||
public ClassLoader getClassLoader() | |||||
{ | |||||
return m_classLoader; | |||||
} | |||||
/** | |||||
* Deploys everything in the type library. | |||||
*/ | |||||
public void deployAll() | |||||
throws DeploymentException | |||||
{ | |||||
// Deploy types | |||||
for( int i = 0; i < m_descriptors.length; i++ ) | |||||
{ | |||||
TypeDescriptor descriptor = m_descriptors[ i ]; | |||||
deployTypes( descriptor ); | |||||
} | |||||
// Deploy services | |||||
for( int i = 0; i < m_services.length; i++ ) | |||||
{ | |||||
final ServiceDescriptor descriptor = m_services[ i ]; | |||||
deployServices( descriptor ); | |||||
} | |||||
} | |||||
/** | |||||
* Deploys a single type in the type library. | |||||
*/ | |||||
public void deployType( final String roleShorthand, final String typeName ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
// Locate the definition for the type | |||||
for( int i = 0; i < m_descriptors.length; i++ ) | |||||
{ | |||||
final TypeDescriptor descriptor = m_descriptors[ i ]; | |||||
final TypeDefinition[] definitions = descriptor.getDefinitions(); | |||||
for( int j = 0; j < definitions.length; j++ ) | |||||
{ | |||||
TypeDefinition definition = definitions[ j ]; | |||||
if( definition.getRole().equals( roleShorthand ) | |||||
&& definition.getName().equals( typeName ) ) | |||||
{ | |||||
// Found the definition - deploy it. Note that we | |||||
// keep looking for matching types, and let the deployer | |||||
// deal with duplicates | |||||
m_deployer.deployType( this, definition ); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "deploy-type.error", roleShorthand, typeName ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Deploys a single type from the type library. | |||||
*/ | |||||
public void deployType( final TypeDefinition typeDef ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
m_deployer.deployType( this, typeDef ); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "deploy-type.error", | |||||
typeDef.getRole(), typeDef.getName() ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Builds descriptors. | |||||
*/ | |||||
private ArrayList buildDescriptors( final ArrayList urls, | |||||
final DescriptorBuilder builder, | |||||
final XMLReader parser, | |||||
final SAXConfigurationHandler handler ) | |||||
throws Exception | |||||
{ | |||||
final ArrayList descriptors = new ArrayList(); | |||||
final int size = urls.size(); | |||||
for( int i = 0; i < size; i++ ) | |||||
{ | |||||
final String url = (String)urls.get( i ); | |||||
// Parse the file | |||||
parser.parse( url ); | |||||
final TypelibDescriptor descriptor = | |||||
builder.createDescriptor( handler.getConfiguration(), url ); | |||||
descriptors.add( descriptor ); | |||||
} | |||||
return descriptors; | |||||
} | |||||
/** | |||||
* Locates all resources of a particular name. | |||||
*/ | |||||
private ArrayList locateResources( final String resource, final URL jarUrl ) | |||||
throws Exception | |||||
{ | |||||
final ArrayList urls = new ArrayList(); | |||||
if( null != jarUrl ) | |||||
{ | |||||
final String systemID = "jar:" + jarUrl + "!/" + resource; | |||||
try | |||||
{ | |||||
// Probe the resource | |||||
final URL url = new URL( systemID ); | |||||
url.openStream().close(); | |||||
// Add to the list | |||||
urls.add( systemID ); | |||||
} | |||||
catch( FileNotFoundException e ) | |||||
{ | |||||
// Ignore | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
final Enumeration enum = m_classLoader.getResources( resource ); | |||||
while( enum.hasMoreElements() ) | |||||
{ | |||||
urls.add( enum.nextElement().toString() ); | |||||
} | |||||
} | |||||
return urls; | |||||
} | |||||
/** | |||||
* Deploys the roles from a role descriptor. | |||||
*/ | |||||
private void deployRoles( final RoleDescriptor descriptor ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "url-deploy-roles.notice", descriptor.getUrl() ); | |||||
getLogger().debug( message ); | |||||
} | |||||
final RoleDefinition[] definitions = descriptor.getDefinitions(); | |||||
for( int i = 0; i < definitions.length; i++ ) | |||||
{ | |||||
final RoleDefinition definition = definitions[ i ]; | |||||
m_deployer.deployRole( this, definition ); | |||||
} | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "deploy-roles.error", descriptor.getUrl() ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Deploys all types from a typelib descriptor. | |||||
*/ | |||||
private void deployTypes( final TypeDescriptor descriptor ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "url-deploy-types.notice", descriptor.getUrl() ); | |||||
getLogger().debug( message ); | |||||
} | |||||
// Deploy all the types | |||||
final TypeDefinition[] definitions = descriptor.getDefinitions(); | |||||
for( int i = 0; i < definitions.length; i++ ) | |||||
{ | |||||
final TypeDefinition definition = definitions[ i ]; | |||||
m_deployer.deployType( this, definition ); | |||||
} | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "deploy-types.error", descriptor.getUrl() ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Deploys all services from a typelib descriptor. | |||||
*/ | |||||
private void deployServices( final ServiceDescriptor descriptor ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "url-deploy-services.notice", descriptor.getUrl() ); | |||||
getLogger().debug( message ); | |||||
} | |||||
// Deploy the services | |||||
final ServiceDefinition[] definitions = descriptor.getDefinitions(); | |||||
for( int i = 0; i < definitions.length; i++ ) | |||||
{ | |||||
final ServiceDefinition definition = definitions[ i ]; | |||||
m_deployer.deployService( this, definition ); | |||||
} | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "deploy-services.error", descriptor.getUrl() ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
} |
@@ -1,27 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
/** | |||||
* Builds a descriptor. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
interface DescriptorBuilder | |||||
{ | |||||
/** | |||||
* Builds a descriptor from a set of configuration. | |||||
*/ | |||||
TypelibDescriptor createDescriptor( Configuration config, | |||||
String descriptorUrl ) | |||||
throws DeploymentException; | |||||
} |
@@ -1,27 +0,0 @@ | |||||
register-converter.notice=Registered converter that converts from {0} to {1}. | |||||
register-type.notice=Registered type {0}/{1}. | |||||
register-role.notice=Registered role {0} with shorthand name {1}. | |||||
url-deploy-types.notice=Registering types from "{0}". | |||||
url-deploy-roles.notice=Registering roles from "{0}". | |||||
url-deploy-services.notice=Registering services from "{0}". | |||||
deploy-from-classloader.error=Could not register types from ClassLoader. | |||||
deploy-from-file.error=Could not register types from type library "{0}". | |||||
deploy-roles.error=Could not register roles from "{0}". | |||||
deploy-types.error=Could not register types from "{0}". | |||||
deploy-services.error=Could not register services from "{0}". | |||||
deploy-converter.error=Could not register converter that converts from {0} to {1}. | |||||
deploy-type.error=Could not register type {0}/{1}. | |||||
unknown-role4name.error=Unknown role "{0}". | |||||
typedef.no-classname.error=Must specify the classname parameter. | |||||
typedef.no-name.error=Must specify name parameter. | |||||
typedef.no-role.error=Must specify type parameter. | |||||
converterdef.no-source.error=Must specify the source-type parameter. | |||||
converterdef.no-destination.error=Must specify the destination-type parameter. | |||||
role-descriptor-version.error=Role descriptor version {0} is incompatible with current version {1}. | |||||
build-role-descriptor.error=Could not build role descriptor from "{0}". | |||||
type-descriptor-version.error=Type library descriptor version {0} is incompatible with current version {1}. | |||||
build-type-descriptor.error=Could not build type library descriptor from "{0}". | |||||
service-descriptor-version.error=Service descriptor version {0} is incompatible with current version {1}. | |||||
build-service-descriptor.error=Could not build service descriptor from "{0}". | |||||
@@ -1,36 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
/** | |||||
* A role definition. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
*/ | |||||
class RoleDefinition | |||||
{ | |||||
private final String m_roleName; | |||||
private final String m_shortHand; | |||||
public RoleDefinition( final String roleName, | |||||
final String shortHand ) | |||||
{ | |||||
m_roleName = roleName; | |||||
m_shortHand = shortHand; | |||||
} | |||||
public String getRoleName() | |||||
{ | |||||
return m_roleName; | |||||
} | |||||
public String getShortHand() | |||||
{ | |||||
return m_shortHand; | |||||
} | |||||
} |
@@ -1,45 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | |||||
* A typelib role descriptor, which defines a set of roles. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class RoleDescriptor | |||||
extends TypelibDescriptor | |||||
{ | |||||
private final List m_definitions = new ArrayList(); | |||||
public RoleDescriptor( final String url ) | |||||
{ | |||||
super( url ); | |||||
} | |||||
/** | |||||
* Returns the role definitions in the descriptor. | |||||
*/ | |||||
public RoleDefinition[] getDefinitions() | |||||
{ | |||||
return (RoleDefinition[])m_definitions.toArray | |||||
( new RoleDefinition[ m_definitions.size() ] ); | |||||
} | |||||
/** | |||||
* Adds a role definition to the descriptor. | |||||
*/ | |||||
public void addDefinition( final RoleDefinition def ) | |||||
{ | |||||
m_definitions.add( def ); | |||||
} | |||||
} |
@@ -1,70 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.Version; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
/** | |||||
* Builds typelib role descriptors. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class RoleDescriptorBuilder | |||||
implements DescriptorBuilder | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( RoleDescriptorBuilder.class ); | |||||
private static final Version ROLE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||||
/** | |||||
* Builds a descriptor from a set of configuration. | |||||
*/ | |||||
public TypelibDescriptor createDescriptor( final Configuration config, | |||||
final String url ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
// Check version | |||||
final String versionString = config.getAttribute( "version" ); | |||||
final Version version = Version.getVersion( versionString ); | |||||
if( !ROLE_DESCRIPTOR_VERSION.complies( version ) ) | |||||
{ | |||||
final String message = REZ.getString( "role-descriptor-version.error", | |||||
version, ROLE_DESCRIPTOR_VERSION ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
// Assemble the descriptor | |||||
final RoleDescriptor descriptor = new RoleDescriptor( url ); | |||||
// Extract each of the role elements | |||||
final Configuration[] types = config.getChildren( "role" ); | |||||
for( int i = 0; i < types.length; i++ ) | |||||
{ | |||||
final String name = types[ i ].getAttribute( "shorthand" ); | |||||
final String role = types[ i ].getAttribute( "name" ); | |||||
final RoleDefinition roleDef = new RoleDefinition( role, name ); | |||||
descriptor.addDefinition( roleDef ); | |||||
} | |||||
return descriptor; | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "build-role-descriptor.error", url ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
} |
@@ -1,56 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
/** | |||||
* A service definition. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class ServiceDefinition | |||||
{ | |||||
private final String m_roleShorthand; | |||||
private final String m_factoryClass; | |||||
private final Configuration m_config; | |||||
public ServiceDefinition( final String roleShorthand, | |||||
final String factoryClass, | |||||
final Configuration config ) | |||||
{ | |||||
m_roleShorthand = roleShorthand; | |||||
m_factoryClass = factoryClass; | |||||
m_config = config; | |||||
} | |||||
/** | |||||
* Returns the role that the service implements. | |||||
*/ | |||||
public String getRoleShorthand() | |||||
{ | |||||
return m_roleShorthand; | |||||
} | |||||
/** | |||||
* Returns the name of the factory class for creating the service. | |||||
*/ | |||||
public String getFactoryClass() | |||||
{ | |||||
return m_factoryClass; | |||||
} | |||||
/** | |||||
* Returns the service configuration. | |||||
*/ | |||||
public Configuration getConfig() | |||||
{ | |||||
return m_config; | |||||
} | |||||
} |
@@ -1,39 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | |||||
* A typelib service descriptor, which defines a set of services. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class ServiceDescriptor | |||||
extends TypelibDescriptor | |||||
{ | |||||
private final List m_services = new ArrayList(); | |||||
public ServiceDescriptor( final String url ) | |||||
{ | |||||
super( url ); | |||||
} | |||||
public ServiceDefinition[] getDefinitions() | |||||
{ | |||||
return (ServiceDefinition[])m_services.toArray | |||||
( new ServiceDefinition[ m_services.size() ] ); | |||||
} | |||||
public void addDefinition( final ServiceDefinition definition ) | |||||
{ | |||||
m_services.add( definition ); | |||||
} | |||||
} |
@@ -1,72 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.Version; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
/** | |||||
* Builds typelib service descriptors. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class ServiceDescriptorBuilder | |||||
implements DescriptorBuilder | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( ServiceDescriptorBuilder.class ); | |||||
private static final Version SERVICE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||||
/** | |||||
* Builds a descriptor from a set of configuration. | |||||
*/ | |||||
public TypelibDescriptor createDescriptor( final Configuration config, | |||||
final String url ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
// Check version | |||||
final String versionString = config.getAttribute( "version" ); | |||||
final Version version = Version.getVersion( versionString ); | |||||
if( !SERVICE_DESCRIPTOR_VERSION.complies( version ) ) | |||||
{ | |||||
final String message = REZ.getString( "service-descriptor-version.error", | |||||
version, SERVICE_DESCRIPTOR_VERSION ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
// Build the descriptor | |||||
final ServiceDescriptor descriptor = new ServiceDescriptor( url ); | |||||
// Add the service definitions | |||||
final Configuration[] elements = config.getChildren(); | |||||
for( int i = 0; i < elements.length; i++ ) | |||||
{ | |||||
final Configuration element = elements[ i ]; | |||||
final String roleShorthand = element.getName(); | |||||
final String factoryClassName = element.getAttribute( "factory" ); | |||||
final ServiceDefinition definition = | |||||
new ServiceDefinition( roleShorthand, factoryClassName, config ); | |||||
descriptor.addDefinition( definition ); | |||||
} | |||||
return descriptor; | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "build-service-descriptor.error", url ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
} |
@@ -1,40 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||||
/** | |||||
* A typelib type descriptor, which defines a set of types. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class TypeDescriptor | |||||
extends TypelibDescriptor | |||||
{ | |||||
private final List m_definitions = new ArrayList(); | |||||
public TypeDescriptor( final String url ) | |||||
{ | |||||
super( url ); | |||||
} | |||||
public TypeDefinition[] getDefinitions() | |||||
{ | |||||
return (TypeDefinition[])m_definitions.toArray | |||||
( new TypeDefinition[ m_definitions.size() ] ); | |||||
} | |||||
public void addDefinition( final TypeDefinition def ) | |||||
{ | |||||
m_definitions.add( def ); | |||||
} | |||||
} |
@@ -1,96 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.Version; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
import org.apache.myrmidon.interfaces.deployer.ConverterDefinition; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||||
/** | |||||
* Builds typelib type descriptors. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class TypeDescriptorBuilder | |||||
implements DescriptorBuilder | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( TypeDescriptorBuilder.class ); | |||||
private static final Version TYPE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||||
/** | |||||
* Builds a descriptor from a set of configuration. | |||||
*/ | |||||
public TypelibDescriptor createDescriptor( final Configuration config, | |||||
final String url ) | |||||
throws DeploymentException | |||||
{ | |||||
try | |||||
{ | |||||
// Check version | |||||
final String versionString = config.getAttribute( "version" ); | |||||
final Version version = Version.getVersion( versionString ); | |||||
if( !TYPE_DESCRIPTOR_VERSION.complies( version ) ) | |||||
{ | |||||
final String message = REZ.getString( "type-descriptor-version.error", | |||||
version, TYPE_DESCRIPTOR_VERSION ); | |||||
throw new DeploymentException( message ); | |||||
} | |||||
// Assemble the descriptor | |||||
final TypeDescriptor descriptor = new TypeDescriptor( url ); | |||||
// Extract each of the types elements | |||||
final Configuration[] typeEntries = config.getChild( "types" ).getChildren(); | |||||
for( int i = 0; i < typeEntries.length; i++ ) | |||||
{ | |||||
final Configuration typeEntry = typeEntries[ i ]; | |||||
final TypeDefinition typeDef = createTypeDefinition( typeEntry ); | |||||
descriptor.addDefinition( typeDef ); | |||||
} | |||||
return descriptor; | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "build-type-descriptor.error", url ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Creates a type definition. | |||||
*/ | |||||
private TypeDefinition createTypeDefinition( final Configuration configuration ) | |||||
throws ConfigurationException | |||||
{ | |||||
final String roleShorthand = configuration.getName(); | |||||
if( roleShorthand.equals( "converter" ) ) | |||||
{ | |||||
// A converter definition | |||||
final String className = configuration.getAttribute( "classname" ); | |||||
final String source = configuration.getAttribute( "source" ); | |||||
final String destination = configuration.getAttribute( "destination" ); | |||||
return new ConverterDefinition( className, source, destination ); | |||||
} | |||||
else | |||||
{ | |||||
// A type definition | |||||
final String typeName = configuration.getAttribute( "name" ); | |||||
final String className = configuration.getAttribute( "classname" ); | |||||
return new TypeDefinition( typeName, roleShorthand, className ); | |||||
} | |||||
} | |||||
} |
@@ -1,32 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.deployer; | |||||
/** | |||||
* A descriptor from a typelib. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class TypelibDescriptor | |||||
{ | |||||
private final String m_url; | |||||
protected TypelibDescriptor( final String url ) | |||||
{ | |||||
m_url = url; | |||||
} | |||||
/** | |||||
* Returns the descriptor URL. | |||||
*/ | |||||
public String getUrl() | |||||
{ | |||||
return m_url; | |||||
} | |||||
} |
@@ -1,454 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.embeddor; | |||||
import java.io.File; | |||||
import java.io.FilenameFilter; | |||||
import java.util.ArrayList; | |||||
import java.util.Iterator; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import org.apache.aut.converter.Converter; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.excalibur.io.ExtensionFileFilter; | |||||
import org.apache.avalon.excalibur.io.FileUtil; | |||||
import org.apache.avalon.framework.CascadingException; | |||||
import org.apache.avalon.framework.context.Contextualizable; | |||||
import org.apache.avalon.framework.context.Context; | |||||
import org.apache.avalon.framework.context.ContextException; | |||||
import org.apache.avalon.framework.activity.Disposable; | |||||
import org.apache.avalon.framework.activity.Initializable; | |||||
import org.apache.avalon.framework.activity.Startable; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.avalon.framework.parameters.Parameterizable; | |||||
import org.apache.avalon.framework.parameters.Parameters; | |||||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||||
import org.apache.myrmidon.interfaces.builder.ProjectBuilder; | |||||
import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||||
import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||||
import org.apache.myrmidon.interfaces.deployer.Deployer; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||||
import org.apache.myrmidon.interfaces.embeddor.Embeddor; | |||||
import org.apache.myrmidon.interfaces.executor.Executor; | |||||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
import org.apache.myrmidon.interfaces.executor.ExecutionContainer; | |||||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||||
import org.apache.myrmidon.interfaces.model.Project; | |||||
import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
import org.apache.myrmidon.interfaces.service.MultiSourceServiceManager; | |||||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||||
import org.apache.myrmidon.listeners.ProjectListener; | |||||
import org.apache.myrmidon.components.workspace.DefaultExecutionFrame; | |||||
import org.apache.myrmidon.components.store.DefaultPropertyStore; | |||||
/** | |||||
* Default implementation of Embeddor. | |||||
* Instantiate this to embed inside other applications. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultEmbeddor | |||||
extends AbstractLogEnabled | |||||
implements Embeddor, Contextualizable, Initializable, Startable, Disposable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultEmbeddor.class ); | |||||
/** Package containing the default component implementations. */ | |||||
private static final String PREFIX = "org.apache.myrmidon.components."; | |||||
private Deployer m_deployer; | |||||
private TypeManager m_typeManager; | |||||
private MultiSourceServiceManager m_workspaceServiceManager; | |||||
private List m_components = new ArrayList(); | |||||
private DefaultServiceManager m_serviceManager = new DefaultServiceManager(); | |||||
private Context m_context; | |||||
/** | |||||
* Setup basic properties of engine. | |||||
* Called before init() and can be used to specify alternate components in system. | |||||
*/ | |||||
public void contextualize( final Context context ) throws ContextException | |||||
{ | |||||
m_context = context; | |||||
} | |||||
/** | |||||
* Builds a project. | |||||
*/ | |||||
public Project createProject( final String location, | |||||
final String type, | |||||
final Parameters parameters ) | |||||
throws Exception | |||||
{ | |||||
try | |||||
{ | |||||
String projectType = type; | |||||
if( null == projectType ) | |||||
{ | |||||
projectType = FileUtil.getExtension( location ); | |||||
} | |||||
// TODO - reuse the project builders, or dispose them | |||||
final ProjectBuilder builder = getProjectBuilder( projectType, parameters ); | |||||
return builder.build( location ); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "create-project.error", location ); | |||||
throw new CascadingException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Creates a project builder for a project type. | |||||
*/ | |||||
private ProjectBuilder getProjectBuilder( final String type, | |||||
final Parameters parameters ) | |||||
throws Exception | |||||
{ | |||||
final TypeFactory factory = m_typeManager.getFactory( ProjectBuilder.ROLE ); | |||||
final ProjectBuilder builder = (ProjectBuilder)factory.create( type ); | |||||
setupObject( builder, m_serviceManager, parameters ); | |||||
return builder; | |||||
} | |||||
/** | |||||
* Creates a workspace. | |||||
*/ | |||||
public Workspace createWorkspace( final Map properties ) | |||||
throws Exception | |||||
{ | |||||
final Workspace workspace = | |||||
(Workspace)createService( Workspace.class, PREFIX + "workspace.DefaultWorkspace" ); | |||||
setupObject( workspace, m_workspaceServiceManager, null ); | |||||
// Create the property store | |||||
final PropertyStore propStore = createBaseStore( properties ); | |||||
// Create an execution frame, and attach it to the workspace | |||||
final ExecutionFrame frame = | |||||
new DefaultExecutionFrame( getLogger(), | |||||
propStore, | |||||
m_workspaceServiceManager); | |||||
( (ExecutionContainer)workspace ).setRootExecutionFrame( frame ); | |||||
// TODO - should keep track of workspaces, to dispose them later | |||||
return workspace; | |||||
} | |||||
/** | |||||
* Creates a project listener. | |||||
* | |||||
* @param name The shorthand name of the listener. | |||||
* @return the listener. | |||||
*/ | |||||
public ProjectListener createListener( final String name ) | |||||
throws Exception | |||||
{ | |||||
final TypeFactory factory = m_typeManager.getFactory( ProjectListener.ROLE ); | |||||
return (ProjectListener)factory.create( name ); | |||||
} | |||||
/** | |||||
* Initialize the system. | |||||
* | |||||
* @exception Exception if an error occurs | |||||
*/ | |||||
public void initialize() | |||||
throws Exception | |||||
{ | |||||
// setup the root components | |||||
setupComponents(); | |||||
// locate the components we need | |||||
m_deployer = (Deployer)m_serviceManager.lookup( Deployer.ROLE ); | |||||
m_typeManager = (TypeManager)m_serviceManager.lookup( TypeManager.ROLE ); | |||||
// setup a service manager that creates the project services | |||||
final ServiceManager projServiceManager | |||||
= (ServiceManager)createService( ServiceManager.class, | |||||
PREFIX + "service.InstantiatingServiceManager" ); | |||||
setupObject( projServiceManager, m_serviceManager, null ); | |||||
m_components.add( projServiceManager ); | |||||
// setup a service manager to be used by workspaces | |||||
m_workspaceServiceManager = new MultiSourceServiceManager(); | |||||
m_workspaceServiceManager.add( projServiceManager ); | |||||
m_workspaceServiceManager.add( m_serviceManager ); | |||||
} | |||||
public void start() | |||||
throws Exception | |||||
{ | |||||
// Deploy all type libraries found in the classpath | |||||
final ClassLoader libClassloader = getClass().getClassLoader(); | |||||
final TypeDeployer typeDeployer = m_deployer.createDeployer( libClassloader ); | |||||
typeDeployer.deployAll(); | |||||
// Deploy all type libraries in the lib directory | |||||
final ExtensionFileFilter filter = new ExtensionFileFilter( ".atl" ); | |||||
final File[] taskLibDirs = (File[])m_context.get( "myrmidon.lib.path" ); | |||||
deployFromDirectories( m_deployer, taskLibDirs, filter ); | |||||
} | |||||
/** | |||||
* Stops the engine. | |||||
*/ | |||||
public void stop() | |||||
{ | |||||
//TODO - Undeploy all the tasks by killing ExecutionFrame??? | |||||
} | |||||
/** | |||||
* Dispose engine. | |||||
*/ | |||||
public void dispose() | |||||
{ | |||||
// Dispose any disposable components | |||||
for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | |||||
{ | |||||
Object component = iterator.next(); | |||||
if( component instanceof Disposable ) | |||||
{ | |||||
final Disposable disposable = (Disposable)component; | |||||
disposable.dispose(); | |||||
} | |||||
} | |||||
// Ditch everything | |||||
m_components = null; | |||||
m_deployer = null; | |||||
m_serviceManager = null; | |||||
m_context = null; | |||||
} | |||||
/** | |||||
* Create all required components. | |||||
*/ | |||||
private void setupComponents() | |||||
throws Exception | |||||
{ | |||||
// Create the components | |||||
createComponent( ExtensionManager.class, PREFIX + "extensions.DefaultExtensionManager" ); | |||||
final Object converter = | |||||
createComponent( Converter.class, PREFIX + "converter.DefaultMasterConverter" ); | |||||
m_serviceManager.put( ConverterRegistry.ROLE, converter ); | |||||
createComponent( Configurer.class, PREFIX + "configurer.DefaultConfigurer" ); | |||||
createComponent( TypeManager.class, PREFIX + "type.DefaultTypeManager" ); | |||||
createComponent( RoleManager.class, PREFIX + "role.DefaultRoleManager" ); | |||||
createComponent( AspectManager.class, PREFIX + "aspect.DefaultAspectManager" ); | |||||
createComponent( Deployer.class, PREFIX + "deployer.DefaultDeployer" ); | |||||
createComponent( ClassLoaderManager.class, | |||||
PREFIX + "classloader.DefaultClassLoaderManager" ); | |||||
createComponent( Executor.class, PREFIX + "executor.AspectAwareExecutor" ); | |||||
createComponent( PropertyResolver.class, PREFIX + "property.DefaultPropertyResolver" ); | |||||
m_serviceManager.put( Embeddor.ROLE, this ); | |||||
// Setup the components | |||||
for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | |||||
{ | |||||
final Object component = iterator.next(); | |||||
setupObject( component, m_serviceManager, null ); | |||||
} | |||||
} | |||||
/** | |||||
* Creates a component. | |||||
*/ | |||||
private Object createComponent( final Class roleType, | |||||
final String defaultImpl ) | |||||
throws Exception | |||||
{ | |||||
final Object component = createService( roleType, defaultImpl ); | |||||
m_serviceManager.put( roleType.getName(), component ); | |||||
m_components.add( component ); | |||||
return component; | |||||
} | |||||
/** | |||||
* Create a component that implements an interface. | |||||
* | |||||
* @param roleType the name of interface/type | |||||
* @param defaultImpl the classname of the default implementation | |||||
* @return the created object | |||||
* @exception Exception if an error occurs | |||||
*/ | |||||
private Object createService( final Class roleType, final String defaultImpl ) | |||||
throws Exception | |||||
{ | |||||
// TODO - need to be able to provide different implementations | |||||
final String className = defaultImpl; | |||||
try | |||||
{ | |||||
final Object object = Class.forName( className ).newInstance(); | |||||
if( !roleType.isInstance( object ) ) | |||||
{ | |||||
final String message = REZ.getString( "bad-type.error", | |||||
className, roleType.getName() ); | |||||
throw new Exception( message ); | |||||
} | |||||
return object; | |||||
} | |||||
catch( final IllegalAccessException iae ) | |||||
{ | |||||
final String message = REZ.getString( "bad-ctor.error", | |||||
roleType.getName(), className ); | |||||
throw new Exception( message ); | |||||
} | |||||
catch( final InstantiationException ie ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "no-instantiate.error", roleType.getName(), className ); | |||||
throw new Exception( message ); | |||||
} | |||||
catch( final ClassNotFoundException cnfe ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "no-class.error", roleType.getName(), className ); | |||||
throw new Exception( message ); | |||||
} | |||||
} | |||||
/** | |||||
* Sets-up an object by running it through the log-enable, compose, | |||||
* parameterise and initialise lifecycle stages. | |||||
*/ | |||||
private void setupObject( final Object object, | |||||
final ServiceManager serviceManager, | |||||
final Parameters parameters ) | |||||
throws Exception | |||||
{ | |||||
setupLogger( object ); | |||||
if(object instanceof Contextualizable ) | |||||
{ | |||||
( (Contextualizable)object ).contextualize( m_context ); | |||||
} | |||||
if( object instanceof Serviceable ) | |||||
{ | |||||
( (Serviceable)object ).service( serviceManager ); | |||||
} | |||||
if( parameters != null && object instanceof Parameterizable ) | |||||
{ | |||||
( (Parameterizable)object ).parameterize( parameters ); | |||||
} | |||||
if( object instanceof Initializable ) | |||||
{ | |||||
( (Initializable)object ).initialize(); | |||||
} | |||||
} | |||||
/** | |||||
* Deploys all type libraries in a directory. | |||||
*/ | |||||
private void deployFromDirectories( final Deployer deployer, | |||||
final File[] directories, | |||||
final FilenameFilter filter ) | |||||
throws DeploymentException | |||||
{ | |||||
for( int i = 0; i < directories.length; i++ ) | |||||
{ | |||||
File directory = directories[i ]; | |||||
final File[] files = directory.listFiles( filter ); | |||||
if( null != files ) | |||||
{ | |||||
deployFiles( deployer, files ); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Deploys a set of type libraries. | |||||
*/ | |||||
private void deployFiles( final Deployer deployer, final File[] files ) | |||||
throws DeploymentException | |||||
{ | |||||
for( int i = 0; i < files.length; i++ ) | |||||
{ | |||||
final String filename = files[ i ].getName(); | |||||
int index = filename.lastIndexOf( '.' ); | |||||
if( -1 == index ) | |||||
{ | |||||
index = filename.length(); | |||||
} | |||||
try | |||||
{ | |||||
final File file = files[ i ].getCanonicalFile(); | |||||
final TypeDeployer typeDeployer = deployer.createDeployer( file ); | |||||
typeDeployer.deployAll(); | |||||
} | |||||
catch( final DeploymentException de ) | |||||
{ | |||||
throw de; | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "bad-filename.error", files[ i ] ); | |||||
throw new DeploymentException( message, e ); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Creates the root property store for a workspace | |||||
*/ | |||||
private PropertyStore createBaseStore( final Map properties ) | |||||
throws Exception | |||||
{ | |||||
final DefaultPropertyStore store = new DefaultPropertyStore(); | |||||
addToStore( store, properties ); | |||||
//Add system properties so that they overide user-defined properties | |||||
addToStore( store, System.getProperties() ); | |||||
return store; | |||||
} | |||||
/** | |||||
* Helper method to add values to a store. | |||||
* | |||||
* @param store the store | |||||
* @param map the map of names->values | |||||
*/ | |||||
private void addToStore( final PropertyStore store, final Map map ) | |||||
throws Exception | |||||
{ | |||||
final Iterator keys = map.keySet().iterator(); | |||||
while( keys.hasNext() ) | |||||
{ | |||||
final String key = (String)keys.next(); | |||||
final Object value = map.get( key ); | |||||
store.setProperty( key, value ); | |||||
} | |||||
} | |||||
} |
@@ -1,6 +0,0 @@ | |||||
bad-type.error=Object {0} is not an instance of {1}. | |||||
bad-ctor.error=Non-public constructor for {0} {1}. | |||||
no-instantiate.error=Error instantiating class for {0} {1}. | |||||
no-class.error=Could not find the class for {0} ({1}). | |||||
bad-filename.error=Unable to retrieve filename for file {0}. | |||||
create-project.error=Could not load the project definition from {0}. |
@@ -1,337 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.executor; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
import org.apache.avalon.framework.configuration.DefaultConfiguration; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
import org.apache.avalon.framework.parameters.Parameters; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.api.Task; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
/** | |||||
* The AspectAwareExecutor executes the tasks but also calls | |||||
* the aspects helpers. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class AspectAwareExecutor | |||||
extends DefaultExecutor | |||||
implements Serviceable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( AspectAwareExecutor.class ); | |||||
private static final Configuration[] EMPTY_ELEMENTS = new Configuration[ 0 ]; | |||||
private AspectManager m_aspectManager; | |||||
/** | |||||
* Retrieve relevent services. | |||||
* | |||||
* @param serviceManager the ServiceManager | |||||
* @exception ServiceException if an error occurs | |||||
*/ | |||||
public void service( final ServiceManager serviceManager ) | |||||
throws ServiceException | |||||
{ | |||||
m_aspectManager = (AspectManager)serviceManager.lookup( AspectManager.ROLE ); | |||||
} | |||||
public void execute( final Configuration taskModel, final ExecutionFrame frame ) | |||||
throws TaskException | |||||
{ | |||||
try | |||||
{ | |||||
executeTask( taskModel, frame ); | |||||
} | |||||
catch( final TaskException te ) | |||||
{ | |||||
final boolean isError = getAspectManager().error( te ); | |||||
if( !isError ) | |||||
{ | |||||
throw te; | |||||
} | |||||
} | |||||
} | |||||
private void executeTask( final Configuration model, | |||||
final ExecutionFrame frame ) | |||||
throws TaskException | |||||
{ | |||||
try | |||||
{ | |||||
Configuration taskModel = getAspectManager().preCreate( model ); | |||||
taskModel = prepareAspects( taskModel ); | |||||
final String taskName = taskModel.getName(); | |||||
debug( "creating.notice", taskName ); | |||||
final Task task = doCreateTask( taskName, frame ); | |||||
getAspectManager().postCreate( task ); | |||||
debug( "logger.notice", taskName ); | |||||
final Logger logger = frame.getLogger(); | |||||
getAspectManager().preLogEnabled( logger ); | |||||
debug( "contextualizing.notice", taskName ); | |||||
final TaskContext context = doCreateContext( frame ); | |||||
doContextualize( task, taskModel, context, frame ); | |||||
debug( "configuring.notice", taskName ); | |||||
getAspectManager().preConfigure( taskModel ); | |||||
doConfigure( task, taskModel, context, frame ); | |||||
debug( "executing.notice", taskName ); | |||||
getAspectManager().preExecute(); | |||||
doExecute( taskModel, task ); | |||||
getAspectManager().preDestroy(); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
// Wrap in generic error message | |||||
final String message = REZ.getString( "execute.error", | |||||
model.getName(), | |||||
model.getLocation() ); | |||||
throw new TaskException( message, e ); | |||||
} | |||||
} | |||||
protected void doExecute( final Configuration taskModel, final Task task ) | |||||
throws TaskException | |||||
{ | |||||
task.execute(); | |||||
} | |||||
//TODO: Extract and clean taskModel here. | |||||
//Get all parameters from model and provide to appropriate aspect. | |||||
//aspect( final Parameters parameters, final Configuration[] elements ) | |||||
private final Configuration prepareAspects( final Configuration taskModel ) | |||||
throws TaskException | |||||
{ | |||||
final DefaultConfiguration newTaskModel = | |||||
new DefaultConfiguration( taskModel.getName(), taskModel.getLocation() ); | |||||
final HashMap parameterMap = new HashMap(); | |||||
final HashMap elementMap = new HashMap(); | |||||
processAttributes( taskModel, newTaskModel, parameterMap ); | |||||
processElements( taskModel, newTaskModel, elementMap ); | |||||
try | |||||
{ | |||||
newTaskModel.setValue( taskModel.getValue() ); | |||||
} | |||||
catch( final ConfigurationException cee ) | |||||
{ | |||||
//Will never occur | |||||
} | |||||
dispatchAspectsSettings( parameterMap, elementMap ); | |||||
checkForUnusedSettings( parameterMap, elementMap ); | |||||
return newTaskModel; | |||||
} | |||||
private final void dispatchAspectsSettings( final HashMap parameterMap, | |||||
final HashMap elementMap ) | |||||
throws TaskException | |||||
{ | |||||
final String[] names = getAspectManager().getNames(); | |||||
for( int i = 0; i < names.length; i++ ) | |||||
{ | |||||
final ArrayList elementList = (ArrayList)elementMap.remove( names[ i ] ); | |||||
Parameters parameters = (Parameters)parameterMap.remove( names[ i ] ); | |||||
if( null == parameters ) | |||||
{ | |||||
parameters = Parameters.EMPTY_PARAMETERS; | |||||
} | |||||
Configuration[] elements = null; | |||||
if( null == elementList ) | |||||
{ | |||||
elements = EMPTY_ELEMENTS; | |||||
} | |||||
else | |||||
{ | |||||
elements = (Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||||
} | |||||
dispatch( names[ i ], parameters, elements ); | |||||
} | |||||
} | |||||
private final void checkForUnusedSettings( final HashMap parameterMap, | |||||
final HashMap elementMap ) | |||||
throws TaskException | |||||
{ | |||||
if( 0 != parameterMap.size() ) | |||||
{ | |||||
final String[] namespaces = | |||||
(String[])parameterMap.keySet().toArray( new String[ 0 ] ); | |||||
for( int i = 0; i < namespaces.length; i++ ) | |||||
{ | |||||
final String namespace = namespaces[ i ]; | |||||
final Parameters parameters = (Parameters)parameterMap.get( namespace ); | |||||
final ArrayList elementList = (ArrayList)elementMap.remove( namespace ); | |||||
Configuration[] elements = null; | |||||
if( null == elementList ) | |||||
{ | |||||
elements = EMPTY_ELEMENTS; | |||||
} | |||||
else | |||||
{ | |||||
elements = (Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||||
} | |||||
unusedSetting( namespace, parameters, elements ); | |||||
} | |||||
} | |||||
if( 0 != elementMap.size() ) | |||||
{ | |||||
final String[] namespaces = | |||||
(String[])elementMap.keySet().toArray( new String[ 0 ] ); | |||||
for( int i = 0; i < namespaces.length; i++ ) | |||||
{ | |||||
final String namespace = namespaces[ i ]; | |||||
final ArrayList elementList = (ArrayList)elementMap.remove( namespace ); | |||||
final Configuration[] elements = | |||||
(Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||||
unusedSetting( namespace, Parameters.EMPTY_PARAMETERS, elements ); | |||||
} | |||||
} | |||||
} | |||||
private void unusedSetting( final String namespace, | |||||
final Parameters parameters, | |||||
final Configuration[] elements ) | |||||
throws TaskException | |||||
{ | |||||
final String message = | |||||
REZ.getString( "unused-settings.error", | |||||
namespace, | |||||
Integer.toString( parameters.getNames().length ), | |||||
Integer.toString( elements.length ) ); | |||||
throw new TaskException( message ); | |||||
} | |||||
private void dispatch( final String namespace, | |||||
final Parameters parameters, | |||||
final Configuration[] elements ) | |||||
throws TaskException | |||||
{ | |||||
getAspectManager().dispatchAspectSettings( namespace, parameters, elements ); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "dispatch-settings.notice", | |||||
namespace, | |||||
Integer.toString( parameters.getNames().length ), | |||||
Integer.toString( elements.length ) ); | |||||
getLogger().debug( message ); | |||||
} | |||||
} | |||||
private final void processElements( final Configuration taskModel, | |||||
final DefaultConfiguration newTaskModel, | |||||
final HashMap map ) | |||||
{ | |||||
final Configuration[] elements = taskModel.getChildren(); | |||||
for( int i = 0; i < elements.length; i++ ) | |||||
{ | |||||
final String name = elements[ i ].getName(); | |||||
final int index = name.indexOf( ':' ); | |||||
if( -1 == index ) | |||||
{ | |||||
newTaskModel.addChild( elements[ i ] ); | |||||
} | |||||
else | |||||
{ | |||||
final String namespace = name.substring( 0, index ); | |||||
final ArrayList elementSet = getElements( namespace, map ); | |||||
elementSet.add( elements[ i ] ); | |||||
} | |||||
} | |||||
} | |||||
private final void processAttributes( final Configuration taskModel, | |||||
final DefaultConfiguration newTaskModel, | |||||
final HashMap map ) | |||||
{ | |||||
final String[] attributes = taskModel.getAttributeNames(); | |||||
for( int i = 0; i < attributes.length; i++ ) | |||||
{ | |||||
final String name = attributes[ i ]; | |||||
final String value = taskModel.getAttribute( name, null ); | |||||
final int index = name.indexOf( ':' ); | |||||
if( -1 == index ) | |||||
{ | |||||
newTaskModel.setAttribute( name, value ); | |||||
} | |||||
else | |||||
{ | |||||
final String namespace = name.substring( 0, index ); | |||||
final String localName = name.substring( index + 1 ); | |||||
final Parameters parameters = getParameters( namespace, map ); | |||||
parameters.setParameter( localName, value ); | |||||
} | |||||
} | |||||
} | |||||
private final ArrayList getElements( final String namespace, final HashMap map ) | |||||
{ | |||||
ArrayList elements = (ArrayList)map.get( namespace ); | |||||
if( null == elements ) | |||||
{ | |||||
elements = new ArrayList(); | |||||
map.put( namespace, elements ); | |||||
} | |||||
return elements; | |||||
} | |||||
private final Parameters getParameters( final String namespace, final HashMap map ) | |||||
{ | |||||
Parameters parameters = (Parameters)map.get( namespace ); | |||||
if( null == parameters ) | |||||
{ | |||||
parameters = new Parameters(); | |||||
map.put( namespace, parameters ); | |||||
} | |||||
return parameters; | |||||
} | |||||
private final AspectManager getAspectManager() | |||||
{ | |||||
return m_aspectManager; | |||||
} | |||||
} |
@@ -1,141 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.executor; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.myrmidon.api.Task; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.components.workspace.DefaultTaskContext; | |||||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
import org.apache.myrmidon.interfaces.executor.Executor; | |||||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
/** | |||||
* The basic executor that just executes the tasks. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultExecutor | |||||
extends AbstractLogEnabled | |||||
implements Executor | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultExecutor.class ); | |||||
/** | |||||
* Executes a task. | |||||
*/ | |||||
public void execute( final Configuration taskModel, final ExecutionFrame frame ) | |||||
throws TaskException | |||||
{ | |||||
final String taskName = taskModel.getName(); | |||||
try | |||||
{ | |||||
debug( "creating.notice", taskName ); | |||||
final Task task = doCreateTask( taskName, frame ); | |||||
debug( "contextualizing.notice", taskName ); | |||||
final TaskContext context = doCreateContext( frame ); | |||||
doContextualize( task, taskModel, context, frame ); | |||||
debug( "configuring.notice", taskName ); | |||||
doConfigure( task, taskModel, context, frame ); | |||||
debug( "executing.notice", taskName ); | |||||
task.execute(); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
// Wrap in generic error message | |||||
final String message = REZ.getString( "execute.error", | |||||
taskName, taskModel.getLocation() ); | |||||
throw new TaskException( message, e ); | |||||
} | |||||
} | |||||
protected final void debug( final String key, final String taskName ) | |||||
{ | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( key, taskName ); | |||||
getLogger().debug( message ); | |||||
} | |||||
} | |||||
/** | |||||
* Creates a context for the task. | |||||
*/ | |||||
protected TaskContext doCreateContext( final ExecutionFrame frame ) | |||||
{ | |||||
// TODO - need to deactivate the context once the task has finished | |||||
// executing | |||||
return new DefaultTaskContext( frame.getServiceManager(), | |||||
frame.getLogger(), | |||||
frame.getProperties() ); | |||||
} | |||||
/** | |||||
* Creates a task instance. | |||||
*/ | |||||
protected final Task doCreateTask( final String name, final ExecutionFrame frame ) | |||||
throws TaskException | |||||
{ | |||||
try | |||||
{ | |||||
final TypeManager typeManager = (TypeManager)frame.getServiceManager().lookup( TypeManager.ROLE ); | |||||
final TypeFactory factory = typeManager.getFactory( Task.ROLE ); | |||||
return (Task)factory.create( name ); | |||||
} | |||||
catch( final Exception te ) | |||||
{ | |||||
final String message = REZ.getString( "create.error", name ); | |||||
throw new TaskException( message, te ); | |||||
} | |||||
} | |||||
/** | |||||
* Configures a task instance. | |||||
*/ | |||||
protected final void doConfigure( final Task task, | |||||
final Configuration taskModel, | |||||
final TaskContext taskContext, | |||||
final ExecutionFrame frame ) | |||||
throws Exception | |||||
{ | |||||
final Configurer configurer = (Configurer)frame.getServiceManager().lookup( Configurer.ROLE ); | |||||
configurer.configureElement( task, taskModel, taskContext ); | |||||
} | |||||
/** | |||||
* Sets the context for a task. | |||||
*/ | |||||
protected final void doContextualize( final Task task, | |||||
final Configuration taskModel, | |||||
final TaskContext taskContext, | |||||
final ExecutionFrame frame ) | |||||
throws TaskException | |||||
{ | |||||
try | |||||
{ | |||||
task.contextualize( taskContext ); | |||||
} | |||||
catch( final Throwable throwable ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "contextualize.error", taskModel.getName() ); | |||||
throw new TaskException( message, throwable ); | |||||
} | |||||
} | |||||
} |
@@ -1,81 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.executor; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.myrmidon.api.Task; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
/** | |||||
* An executor that just displays the tasks rather than executing them. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class PrintingExecutor | |||||
extends AspectAwareExecutor | |||||
{ | |||||
protected void doExecute( final Configuration taskModel, final Task task ) | |||||
throws TaskException | |||||
{ | |||||
final StringBuffer sb = new StringBuffer(); | |||||
printConfiguration( taskModel, 0, sb ); | |||||
System.out.println( sb.toString() ); | |||||
} | |||||
private void printConfiguration( final Configuration taskModel, | |||||
final int level, | |||||
final StringBuffer sb ) | |||||
{ | |||||
for( int i = 0; i < level; i++ ) | |||||
{ | |||||
sb.append( ' ' ); | |||||
} | |||||
sb.append( '<' ); | |||||
sb.append( taskModel.getName() ); | |||||
final String[] names = taskModel.getAttributeNames(); | |||||
for( int i = 0; i < names.length; i++ ) | |||||
{ | |||||
final String name = names[ i ]; | |||||
final String value = taskModel.getAttribute( name, null ); | |||||
sb.append( ' ' ); | |||||
sb.append( name ); | |||||
sb.append( "=\"" ); | |||||
sb.append( value ); | |||||
sb.append( '\"' ); | |||||
} | |||||
final Configuration[] children = taskModel.getChildren(); | |||||
if( 0 == children.length ) | |||||
{ | |||||
sb.append( "/>\n" ); | |||||
} | |||||
else | |||||
{ | |||||
sb.append( ">\n" ); | |||||
for( int i = 0; i < children.length; i++ ) | |||||
{ | |||||
printConfiguration( children[ i ], level + 1, sb ); | |||||
} | |||||
for( int i = 0; i < level; i++ ) | |||||
{ | |||||
sb.append( ' ' ); | |||||
} | |||||
sb.append( "</" ); | |||||
sb.append( taskModel.getName() ); | |||||
sb.append( ">\n" ); | |||||
} | |||||
} | |||||
} |
@@ -1,11 +0,0 @@ | |||||
creating.notice=Creating {0}. | |||||
contextualizing.notice=Contextualizing {0}. | |||||
configuring.notice=Configuring {0}. | |||||
executing.notice=Executing {0}. | |||||
create.error=Could not create task <{0}>. | |||||
contextualize.error=Could not set the context for task <{0}>. | |||||
execute.error={1}: Could not execute task <{0}>. | |||||
unused-settings.error=Unused aspect settings for namespace {0} (parameterCount={1} elementCount={2}). | |||||
dispatch-settings.notice=Dispatching Aspect Settings to namespace {0} (parameterCount={1} elementCount={2}). |
@@ -1,162 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.extensions; | |||||
import java.io.File; | |||||
import org.apache.avalon.excalibur.extension.DefaultPackageRepository; | |||||
import org.apache.avalon.excalibur.extension.Extension; | |||||
import org.apache.avalon.excalibur.extension.OptionalPackage; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.activity.Disposable; | |||||
import org.apache.avalon.framework.activity.Initializable; | |||||
import org.apache.avalon.framework.context.Context; | |||||
import org.apache.avalon.framework.context.ContextException; | |||||
import org.apache.avalon.framework.context.Contextualizable; | |||||
import org.apache.avalon.framework.logger.LogEnabled; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||||
/** | |||||
* PhoenixPackageRepository | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultExtensionManager | |||||
extends DefaultPackageRepository | |||||
implements LogEnabled, Contextualizable, Initializable, Disposable, ExtensionManager | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultExtensionManager.class ); | |||||
/** | |||||
* The standard location of tools.jar for IBM/Sun JDKs. | |||||
*/ | |||||
private static final String TOOLS_JAR = | |||||
File.separator + "lib" + File.separator + "tools.jar"; | |||||
/** | |||||
* The path relative to JRE in which tools.jar is located. | |||||
*/ | |||||
private static final String DEBIAN_TOOLS_JAR = | |||||
File.separator + ".." + File.separator + "j2sdk1.3" + | |||||
File.separator + "lib" + File.separator + "tools.jar"; | |||||
private Logger m_logger; | |||||
private File[] m_path; | |||||
public DefaultExtensionManager() | |||||
{ | |||||
super( new File[ 0 ] ); | |||||
} | |||||
public DefaultExtensionManager( final File[] path ) | |||||
{ | |||||
super( path ); | |||||
} | |||||
public void enableLogging( final Logger logger ) | |||||
{ | |||||
m_logger = logger; | |||||
} | |||||
public void contextualize( final Context context ) throws ContextException | |||||
{ | |||||
m_path = (File[])context.get( "myrmidon.ext.path" ); | |||||
} | |||||
public void initialize() | |||||
throws Exception | |||||
{ | |||||
setPath( m_path ); | |||||
scanPath(); | |||||
// Add the JVM's tools.jar as an extension | |||||
final Extension extension = createToolsExtension(); | |||||
final File jar = getToolsJar(); | |||||
final Extension[] available = new Extension[]{extension}; | |||||
final Extension[] required = new Extension[ 0 ]; | |||||
final OptionalPackage toolsPackage = new OptionalPackage( jar, available, required ); | |||||
cacheOptionalPackage( toolsPackage ); | |||||
} | |||||
public void dispose() | |||||
{ | |||||
clearCache(); | |||||
} | |||||
/** | |||||
* Locates the optional package which best matches a required extension. | |||||
* | |||||
* @param extension the extension to locate an optional package | |||||
* @return the optional package, or null if not found. | |||||
*/ | |||||
public OptionalPackage getOptionalPackage( final Extension extension ) | |||||
{ | |||||
final OptionalPackage[] packages = getOptionalPackages( extension ); | |||||
if( null == packages || 0 == packages.length ) return null; | |||||
//TODO: Use heurisitic to find which is best package | |||||
return packages[ 0 ]; | |||||
} | |||||
protected void debug( final String message ) | |||||
{ | |||||
m_logger.debug( message ); | |||||
} | |||||
private File getToolsJar() | |||||
throws Exception | |||||
{ | |||||
final String javaHome = System.getProperty( "java.home" ); | |||||
String jdkHome; | |||||
if( javaHome.endsWith( "jre" ) ) | |||||
{ | |||||
jdkHome = javaHome.substring( 0, javaHome.length() - 4 ); | |||||
} | |||||
else | |||||
{ | |||||
jdkHome = javaHome; | |||||
} | |||||
//We need to search through a few locations to locate tools.jar | |||||
File tools = new File( jdkHome + TOOLS_JAR ); | |||||
if( tools.exists() ) | |||||
{ | |||||
return tools; | |||||
} | |||||
//The path to tools.jar. In some cases $JRE_HOME is not equal to | |||||
//$JAVA_HOME/jre. For example, on Debian, IBM's j2sdk1.3 .deb puts | |||||
//the JRE in /usr/lib/j2sdk1.3, and the JDK in /usr/lib/j2re1.3, | |||||
//tools.jar=${java.home}/../j2sdk1.3/lib/tools.jar | |||||
tools = new File( jdkHome + DEBIAN_TOOLS_JAR ); | |||||
if( !tools.exists() ) | |||||
{ | |||||
final String message = REZ.getString( "extension.missing-tools.error" ); | |||||
throw new Exception( message ); | |||||
} | |||||
return tools; | |||||
} | |||||
private static Extension createToolsExtension() | |||||
{ | |||||
return new Extension( "com.sun.tools", | |||||
"1.0", | |||||
"com.sun", | |||||
"1.0", | |||||
"com.sun", | |||||
"com.sun", | |||||
null ); | |||||
} | |||||
} |
@@ -1,49 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.property; | |||||
import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
/** | |||||
* A {@link PropertyResolver} implementation which resolves properties | |||||
* as per Ant1, ignoring undefined properties. | |||||
* | |||||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
* @version $Revision$ $Date$ | |||||
* | |||||
* @ant.type type="property-resolver" name="classic" | |||||
*/ | |||||
public class ClassicPropertyResolver | |||||
extends DefaultPropertyResolver | |||||
implements PropertyResolver | |||||
{ | |||||
/** | |||||
* Retrieve a value from the specified context using the specified key. | |||||
* If there is no such value, returns the original property reference. | |||||
* | |||||
* @param propertyName the name of the property to retrieve | |||||
* @param context the set of known properties | |||||
*/ | |||||
protected Object getPropertyValue( final String propertyName, | |||||
final TaskContext context ) | |||||
throws TaskException | |||||
{ | |||||
final Object value = context.getProperty( propertyName ); | |||||
if( value != null ) | |||||
{ | |||||
return value; | |||||
} | |||||
else | |||||
{ | |||||
return "${" + propertyName + "}"; | |||||
} | |||||
} | |||||
} |
@@ -1,290 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.property; | |||||
import org.apache.aut.converter.Converter; | |||||
import org.apache.aut.converter.ConverterException; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
/** | |||||
* Base class for PropertyResolver implementations. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
* @version $Revision$ $Date$ | |||||
* | |||||
* @ant.type type="property-resolver" name="default" | |||||
*/ | |||||
public class DefaultPropertyResolver | |||||
implements PropertyResolver, Serviceable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultPropertyResolver.class ); | |||||
private Converter m_converter; | |||||
public void service( final ServiceManager serviceManager ) throws ServiceException | |||||
{ | |||||
m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||||
} | |||||
/** | |||||
* Resolve a string property. This evaluates all property | |||||
* substitutions based on specified context. | |||||
* | |||||
* If the content contains a single property reference, then the property value | |||||
* <code>Object</code> itself is returned. | |||||
* Otherwise, a <code>String</code> is returned, comprising the supplied | |||||
* content, with all property references replaced with the result of | |||||
* <code>toString()</code> called on the property value. | |||||
* | |||||
* @param content the property to resolve | |||||
* @param context the context in which to resolve property | |||||
* @return the reolved property | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
public Object resolveProperties( final String content, | |||||
final TaskContext context ) | |||||
throws TaskException | |||||
{ | |||||
int start = findNextProperty( content, 0 ); | |||||
if( -1 == start ) | |||||
{ | |||||
return content; | |||||
} | |||||
int end = findEnding( content, start ); | |||||
final int length = content.length(); | |||||
if( 0 == start && end == ( length - 1 ) ) | |||||
{ | |||||
return getPropertyValue( content.substring( start + 2, end ), | |||||
context ); | |||||
} | |||||
final StringBuffer sb = new StringBuffer( length * 2 ); | |||||
int lastPlace = 0; | |||||
while( true ) | |||||
{ | |||||
final String propertyValue = | |||||
getPropertyStringValue( content.substring( start + 2, end ), | |||||
context ); | |||||
sb.append( content.substring( lastPlace, start ) ); | |||||
sb.append( propertyValue ); | |||||
lastPlace = end + 1; | |||||
start = findNextProperty( content, lastPlace ); | |||||
if( -1 == start ) | |||||
{ | |||||
break; | |||||
} | |||||
end = findEnding( content, start ); | |||||
} | |||||
sb.append( content.substring( lastPlace, length ) ); | |||||
return sb.toString(); | |||||
} | |||||
/** | |||||
* Resolve a string property. This recursively evaluates all property | |||||
* substitutions based on specified context. | |||||
* | |||||
* @param content the property to resolve | |||||
* @param context the context in which to resolve property | |||||
* @return the reolved property | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
private Object recursiveResolveProperty( final String content, | |||||
final TaskContext context ) | |||||
throws TaskException | |||||
{ | |||||
int start = findNextProperty( content, 0 ); | |||||
if( -1 == start ) | |||||
{ | |||||
return content; | |||||
} | |||||
int end = findNestedEnding( content, start ); | |||||
final int length = content.length(); | |||||
if( 0 == start && end == ( length - 1 ) ) | |||||
{ | |||||
final String propertyName = content.substring( start + 2, end ); | |||||
final Object key = recursiveResolveProperty( propertyName, context ); | |||||
return getPropertyValue( key.toString(), context ); | |||||
} | |||||
final StringBuffer sb = new StringBuffer( length * 2 ); | |||||
int lastPlace = 0; | |||||
while( true ) | |||||
{ | |||||
final String propertyName = content.substring( start + 2, end ); | |||||
final Object key = recursiveResolveProperty( propertyName, context ); | |||||
final String value = getPropertyStringValue( key.toString(), context ); | |||||
sb.append( content.substring( lastPlace, start ) ); | |||||
sb.append( value ); | |||||
lastPlace = end + 1; | |||||
start = findNextProperty( content, lastPlace ); | |||||
if( -1 == start ) | |||||
{ | |||||
break; | |||||
} | |||||
end = findNestedEnding( content, start ); | |||||
} | |||||
sb.append( content.substring( lastPlace, length ) ); | |||||
return sb.toString(); | |||||
} | |||||
/** | |||||
* Finds the next occurrance of the start of a Property identifier. | |||||
* @param content the String to search | |||||
* @param currentPosition start location of the search | |||||
* @return the position of the next occurrence, or <code>-1</code> if none | |||||
* was found. | |||||
*/ | |||||
private int findNextProperty( final String content, final int currentPosition ) | |||||
{ | |||||
//TODO: Check if it is commented out | |||||
return content.indexOf( "${", currentPosition ); | |||||
} | |||||
/** | |||||
* Finds the next occurrence of the end of a Property identifier. | |||||
* @param property the String to search | |||||
* @param currentPosition start location of the search | |||||
* @return the position of the next occurrence | |||||
* @throws TaskException if no end was found | |||||
*/ | |||||
private int findEnding( final String property, final int currentPosition ) | |||||
throws TaskException | |||||
{ | |||||
//TODO: Check if it is commented out | |||||
final int index = property.indexOf( '}', currentPosition ); | |||||
if( -1 == index ) | |||||
{ | |||||
final String message = REZ.getString( "prop.mismatched-braces.error" ); | |||||
throw new TaskException( message ); | |||||
} | |||||
return index; | |||||
} | |||||
/** | |||||
* Finds the end of the property identifier at the currentPosition, | |||||
* taking into account nested property identifiers. | |||||
* @param property the String to search | |||||
* @param currentPosition location of the property | |||||
* @return the position of the propery ending. | |||||
* @throws TaskException if the property is not properly ended. | |||||
*/ | |||||
private int findNestedEnding( final String property, final int currentPosition ) | |||||
throws TaskException | |||||
{ | |||||
final int length = property.length(); | |||||
final int start = currentPosition + 2; | |||||
int weight = 1; | |||||
for( int i = start; ( weight > 0 ) && ( i < length ); i++ ) | |||||
{ | |||||
final char ch = property.charAt( i ); | |||||
switch( ch ) | |||||
{ | |||||
case '}': | |||||
//TODO: Check if it is commented out | |||||
weight--; | |||||
if( weight == 0 ) | |||||
{ | |||||
return i; | |||||
} | |||||
break; | |||||
case '$': | |||||
{ | |||||
//TODO: Check if it is commented out | |||||
final int next = i + 1; | |||||
if( next < length && '{' == property.charAt( next ) ) | |||||
{ | |||||
weight++; | |||||
} | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
final String message = REZ.getString( "prop.mismatched-braces.error" ); | |||||
throw new TaskException( message ); | |||||
} | |||||
/** | |||||
* Returns a property's value, converted to a String. | |||||
*/ | |||||
private String getPropertyStringValue( final String propertyName, | |||||
final TaskContext context ) | |||||
throws TaskException | |||||
{ | |||||
final Object value = getPropertyValue( propertyName, context ); | |||||
if( value instanceof String ) | |||||
{ | |||||
return (String)value; | |||||
} | |||||
try | |||||
{ | |||||
return (String)m_converter.convert( String.class, value, context ); | |||||
} | |||||
catch( final ConverterException e ) | |||||
{ | |||||
throw new TaskException( e.getMessage(), e ); | |||||
} | |||||
} | |||||
/** | |||||
* Retrieve a value from the specified context using the specified key. | |||||
* | |||||
* @param propertyName the key of value in context | |||||
* @param context the set of known properties | |||||
* @return the object retrieved from context | |||||
* @exception TaskException if the property is undefined | |||||
*/ | |||||
protected Object getPropertyValue( final String propertyName, | |||||
final TaskContext context ) | |||||
throws TaskException | |||||
{ | |||||
final Object value = context.getProperty( propertyName ); | |||||
if( value != null ) | |||||
{ | |||||
return value; | |||||
} | |||||
final String message = REZ.getString( "prop.missing-value.error", propertyName ); | |||||
throw new TaskException( message ); | |||||
} | |||||
} | |||||
@@ -1,3 +0,0 @@ | |||||
#AbstractPropertyResolver | |||||
prop.mismatched-braces.error=Malformed property with mismatched }'s. | |||||
prop.missing-value.error=Unknown property "{0}". |
@@ -1,163 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.role; | |||||
import java.util.HashMap; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.myrmidon.interfaces.role.RoleException; | |||||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
/** | |||||
* Interface to manage roles and mapping to names. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version CVS $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultRoleManager | |||||
implements RoleManager | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultRoleManager.class ); | |||||
/** Parent <code>RoleManager</code> for nested resolution */ | |||||
private final RoleManager m_parent; | |||||
/** Map from shorthand name -> RoleInfo. */ | |||||
private final HashMap m_shorthandMap = new HashMap(); | |||||
/** Map from role name -> RoleInfo. */ | |||||
private final HashMap m_nameMap = new HashMap(); | |||||
/** Map from role type -> RoleInfo. */ | |||||
private final HashMap m_typeMap = new HashMap(); | |||||
/** | |||||
* constructor--this RoleManager has no parent. | |||||
*/ | |||||
public DefaultRoleManager() | |||||
{ | |||||
this( null ); | |||||
} | |||||
/** | |||||
* Alternate constructor--this RoleManager has the specified | |||||
* parent. | |||||
* | |||||
* @param parent The parent <code>RoleManager</code>. | |||||
*/ | |||||
public DefaultRoleManager( final RoleManager parent ) | |||||
{ | |||||
m_parent = parent; | |||||
} | |||||
/** | |||||
* Find role based on shorthand name. | |||||
* | |||||
* @param name the shorthand name | |||||
* @return the role, or null if the role cannot be found. | |||||
*/ | |||||
public RoleInfo getRoleByShorthandName( final String name ) | |||||
{ | |||||
final RoleInfo role = (RoleInfo)m_shorthandMap.get( name ); | |||||
if( null == role && null != m_parent ) | |||||
{ | |||||
return m_parent.getRoleByShorthandName( name ); | |||||
} | |||||
return role; | |||||
} | |||||
/** | |||||
* Find role based on role type. | |||||
* | |||||
* @param type the role type. | |||||
* @return the role, or null if the role cannot be found. | |||||
*/ | |||||
public RoleInfo getRoleByType( final Class type ) | |||||
{ | |||||
final RoleInfo role = (RoleInfo)m_typeMap.get( type ); | |||||
if( null == role && null != m_parent ) | |||||
{ | |||||
return m_parent.getRoleByType( type ); | |||||
} | |||||
return role; | |||||
} | |||||
/** | |||||
* Find role based on name. | |||||
* | |||||
* @param name the role name | |||||
* @return the role, or null if the role cannot be found. | |||||
*/ | |||||
public RoleInfo getRole( final String name ) | |||||
{ | |||||
final RoleInfo role = (RoleInfo)m_nameMap.get( name ); | |||||
if( null == role && null != m_parent ) | |||||
{ | |||||
return m_parent.getRole( name ); | |||||
} | |||||
return role; | |||||
} | |||||
/** | |||||
* Adds a role definition. | |||||
*/ | |||||
public void addRole( final RoleInfo role ) throws RoleException | |||||
{ | |||||
// Check for duplicate role names | |||||
final String roleName = role.getName(); | |||||
RoleInfo oldRole = (RoleInfo)m_nameMap.get( roleName ); | |||||
if( null != oldRole && !oldRole.equals( role ) ) | |||||
{ | |||||
final String message = REZ.getString( "duplicate-role.error", roleName ); | |||||
throw new RoleException( message ); | |||||
} | |||||
// Check for duplicate shorthand names | |||||
final String shorthand = role.getShorthand(); | |||||
if( shorthand != null ) | |||||
{ | |||||
oldRole = (RoleInfo)m_shorthandMap.get( shorthand ); | |||||
if( null != oldRole && !oldRole.equals( role ) ) | |||||
{ | |||||
final String message = REZ.getString( "duplicate-shorthand.error", shorthand ); | |||||
throw new RoleException( message ); | |||||
} | |||||
} | |||||
// Check for duplicate types | |||||
final Class roleType = role.getType(); | |||||
if( roleType != null ) | |||||
{ | |||||
oldRole = (RoleInfo)m_typeMap.get( roleType ); | |||||
if( null != oldRole && !oldRole.equals( role ) ) | |||||
{ | |||||
final String message = REZ.getString( "duplicate-type.error", roleType.getName() ); | |||||
throw new RoleException( message ); | |||||
} | |||||
} | |||||
// Add the role to the maps | |||||
m_nameMap.put( roleName, role ); | |||||
if( shorthand != null ) | |||||
{ | |||||
m_shorthandMap.put( shorthand, role ); | |||||
} | |||||
if( roleType != null ) | |||||
{ | |||||
m_typeMap.put( roleType, role ); | |||||
} | |||||
} | |||||
} |
@@ -1,3 +0,0 @@ | |||||
duplicate-shorthand.error=Duplicate roles with shorthand name "{0}". | |||||
duplicate-type.error=Duplicate roles with type "{0}". | |||||
duplicate-role.error=Duplicate roles with name "{0}". |
@@ -1,248 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.service; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.Iterator; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.activity.Disposable; | |||||
import org.apache.avalon.framework.activity.Initializable; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.avalon.framework.parameters.ParameterException; | |||||
import org.apache.avalon.framework.parameters.Parameterizable; | |||||
import org.apache.avalon.framework.parameters.Parameters; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.avalon.framework.context.Contextualizable; | |||||
import org.apache.avalon.framework.context.Context; | |||||
import org.apache.avalon.framework.context.ContextException; | |||||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||||
import org.apache.myrmidon.interfaces.type.TypeException; | |||||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
/** | |||||
* A service manager implementation, which creates service instances on demand. | |||||
* | |||||
* <p>This manager creates service instances, using a {@link ServiceFactory}, | |||||
* and running the service instances through the service lifecycle: | |||||
* <ul> | |||||
* <li>log enable | |||||
* <li>contextualise | |||||
* <li>service | |||||
* <li>parameterise | |||||
* <li>initialise | |||||
* <li>use | |||||
* <li>dispose | |||||
* </ul> | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class InstantiatingServiceManager | |||||
extends AbstractLogEnabled | |||||
implements ServiceManager, Contextualizable, Parameterizable, Serviceable, Disposable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( InstantiatingServiceManager.class ); | |||||
/** Map from service class -> service object. */ | |||||
private Map m_services = new HashMap(); | |||||
/** The objects (services and factories) that have been created by this mgr. */ | |||||
private List m_objects = new ArrayList(); | |||||
/** Other services used by this service manager. */ | |||||
private TypeFactory m_typeFactory; | |||||
private RoleManager m_roleManager; | |||||
private ServiceManager m_serviceManager; | |||||
private Parameters m_parameters; | |||||
private TypeManager m_typeManager; | |||||
private Context m_context; | |||||
public void contextualize( final Context context ) throws ContextException | |||||
{ | |||||
m_context = context; | |||||
} | |||||
public void parameterize( final Parameters parameters ) throws ParameterException | |||||
{ | |||||
m_parameters = parameters; | |||||
} | |||||
/** | |||||
* Pass the <code>ServiceManager</code> to the <code>servicable</code>. | |||||
* The <code>Servicable</code> implementation should use the specified | |||||
* <code>ServiceManager</code> to acquire the components it needs for | |||||
* execution. | |||||
* | |||||
* @param manager The <code>ServiceManager</code> which this | |||||
* <code>Servicable</code> uses. | |||||
*/ | |||||
public void service( final ServiceManager manager ) | |||||
throws ServiceException | |||||
{ | |||||
m_serviceManager = manager; | |||||
m_roleManager = (RoleManager)manager.lookup( RoleManager.ROLE ); | |||||
m_typeManager = (TypeManager)manager.lookup( TypeManager.ROLE ); | |||||
} | |||||
/** | |||||
* Disposes this service manager, and all services created by it. | |||||
*/ | |||||
public void dispose() | |||||
{ | |||||
// Dispose the services | |||||
for( Iterator iterator = m_objects.iterator(); iterator.hasNext(); ) | |||||
{ | |||||
final Object object = iterator.next(); | |||||
if( object instanceof Disposable ) | |||||
{ | |||||
( (Disposable)object ).dispose(); | |||||
} | |||||
} | |||||
// Ditch state | |||||
m_services = null; | |||||
m_typeFactory = null; | |||||
m_objects = null; | |||||
m_parameters = null; | |||||
m_roleManager = null; | |||||
m_serviceManager = null; | |||||
} | |||||
/** | |||||
* Determines if this service manager contains a particular service. | |||||
*/ | |||||
public boolean hasService( final String serviceRole ) | |||||
{ | |||||
// If we have already instantiated the service, or if we know how | |||||
// to instantiate it, then return true | |||||
if( m_services.containsKey( serviceRole ) ) | |||||
{ | |||||
return true; | |||||
} | |||||
try | |||||
{ | |||||
return getFactory().canCreate( serviceRole ); | |||||
} | |||||
catch( TypeException e ) | |||||
{ | |||||
// Throw away exception - yuck | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* Locates the type factory to use to instantiate service factories. | |||||
*/ | |||||
private TypeFactory getFactory() throws TypeException | |||||
{ | |||||
if( m_typeFactory == null ) | |||||
{ | |||||
m_typeFactory = m_typeManager.getFactory( ServiceFactory.ROLE ); | |||||
} | |||||
return m_typeFactory; | |||||
} | |||||
/** | |||||
* Locates a service instance. | |||||
*/ | |||||
public Object lookup( final String serviceRole ) | |||||
throws ServiceException | |||||
{ | |||||
Object service = m_services.get( serviceRole ); | |||||
if( service == null ) | |||||
{ | |||||
// Create the service | |||||
service = createService( serviceRole ); | |||||
m_services.put( serviceRole, service ); | |||||
} | |||||
return service; | |||||
} | |||||
/** | |||||
* Releases a service. | |||||
*/ | |||||
public void release( final Object service ) | |||||
{ | |||||
} | |||||
/** | |||||
* Creates the service object for a service role. | |||||
*/ | |||||
private Object createService( final String serviceRole ) throws ServiceException | |||||
{ | |||||
try | |||||
{ | |||||
// Create the factory | |||||
final ServiceFactory factory = (ServiceFactory)getFactory().create( serviceRole ); | |||||
setupObject( factory ); | |||||
// Create the service | |||||
final Object service = factory.createService(); | |||||
// Check the service is assignable to the role type | |||||
final RoleInfo roleInfo = m_roleManager.getRole( serviceRole ); | |||||
final Class serviceType = roleInfo.getType(); | |||||
if( serviceType != null && !serviceType.isInstance( service ) ) | |||||
{ | |||||
final String message = REZ.getString( "mismatched-service-type.error", | |||||
serviceRole, service.getClass().getName() ); | |||||
throw new ServiceException( message ); | |||||
} | |||||
setupObject( service ); | |||||
return service; | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "create-service.error", serviceRole ); | |||||
throw new ServiceException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Sets-up an object, taking it through the lifecycle steps. | |||||
*/ | |||||
private void setupObject( final Object object ) | |||||
throws Exception | |||||
{ | |||||
setupLogger( object ); | |||||
if( m_context != null && object instanceof Contextualizable ) | |||||
{ | |||||
( (Contextualizable)object ).contextualize( m_context ); | |||||
} | |||||
if( object instanceof Serviceable ) | |||||
{ | |||||
( (Serviceable)object ).service( m_serviceManager ); | |||||
} | |||||
if( m_parameters != null && object instanceof Parameterizable ) | |||||
{ | |||||
( (Parameterizable)object ).parameterize( m_parameters ); | |||||
} | |||||
if( object instanceof Initializable ) | |||||
{ | |||||
( (Initializable)object ).initialize(); | |||||
} | |||||
m_objects.add( object ); | |||||
} | |||||
} |
@@ -1,3 +0,0 @@ | |||||
unknown-service-type.error=Unknown service "{0}". | |||||
mismatched-service-type.error=Service factory for service "{0}" produced an object of unexpected type {1}. | |||||
create-service.error=Could not create service "{0}". |
@@ -1,268 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.store; | |||||
import java.io.File; | |||||
import java.util.HashMap; | |||||
import java.util.Hashtable; | |||||
import java.util.Map; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.interfaces.model.DefaultNameValidator; | |||||
import org.apache.myrmidon.interfaces.model.NameValidator; | |||||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
/** | |||||
* This is the Default implementation of PropertyStore. It follows | |||||
* the following rules; | |||||
* | |||||
* <ul> | |||||
* <li>The property names must pass DefaultNameValidator checks</li> | |||||
* <li>The store is mutable</li> | |||||
* <li>If the key is TaskContext.NAME then value must be a string.</li> | |||||
* <li>If the key is TaskContext.BASE_DIRECTORY then value must be a key.</li> | |||||
* </ul> | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
* @see org.apache.myrmidon.interfaces.property.PropertyStore | |||||
*/ | |||||
public class DefaultPropertyStore | |||||
implements PropertyStore | |||||
{ | |||||
private final static Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultPropertyStore.class ); | |||||
/** | |||||
* The parent store (may be null). | |||||
*/ | |||||
private final PropertyStore m_parent; | |||||
/** | |||||
* The name validator to check property names against. | |||||
*/ | |||||
private final NameValidator m_validator; | |||||
/** | |||||
* The underlying map where propertys are actually stored. | |||||
*/ | |||||
private final Map m_contextData = new Hashtable(); | |||||
/** | |||||
* Construct a PropertyStore with no parent and | |||||
* default name-validator. | |||||
*/ | |||||
public DefaultPropertyStore() | |||||
{ | |||||
this( "", null, null ); | |||||
} | |||||
/** | |||||
* Construct a PropertyStore with specified parent. | |||||
* | |||||
* @param parent the parent PropertyStore (may be null). | |||||
* @param validator the validator to use to check property names (may be null). | |||||
*/ | |||||
public DefaultPropertyStore( final String name, | |||||
final PropertyStore parent, | |||||
final NameValidator validator ) | |||||
{ | |||||
m_parent = parent; | |||||
NameValidator candidateValidator = validator; | |||||
if( null == candidateValidator ) | |||||
{ | |||||
candidateValidator = createDefaultNameValidator(); | |||||
} | |||||
m_validator = candidateValidator; | |||||
m_contextData.put( TaskContext.NAME, name ); | |||||
} | |||||
/** | |||||
* Set the property with specified name to specified value. | |||||
* The specific implementation will apply various rules | |||||
* before setting the property. | |||||
* | |||||
* @param name the name of property | |||||
* @param value the value of property | |||||
* @throws TaskException if property can not be set | |||||
*/ | |||||
public void setProperty( final String name, final Object value ) | |||||
throws TaskException | |||||
{ | |||||
checkPropertyName( name ); | |||||
checkPropertyValid( name, value ); | |||||
if ( value == null ) | |||||
{ | |||||
m_contextData.remove( name ); | |||||
} | |||||
else | |||||
{ | |||||
m_contextData.put( name, value ); | |||||
} | |||||
} | |||||
/** | |||||
* Return <code>true</code> if the specified property is set. | |||||
* | |||||
* @param name the name of property | |||||
*/ | |||||
public boolean isPropertySet( final String name ) | |||||
{ | |||||
try | |||||
{ | |||||
getProperty( name ); | |||||
return true; | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* Retrieve the value of specified property. | |||||
* Will return null if no such property exists. | |||||
* | |||||
* @param name the name of the property | |||||
* @return the value of the property, or null if no such property | |||||
* @throws TaskException if theres an error retrieving property, such | |||||
* as an invalid property name | |||||
*/ | |||||
public Object getProperty( final String name ) | |||||
throws TaskException | |||||
{ | |||||
Object value = m_contextData.get( name ); | |||||
if( value != null ) | |||||
{ | |||||
return value; | |||||
} | |||||
if( m_parent != null ) | |||||
{ | |||||
return m_parent.getProperty( name ); | |||||
} | |||||
final String message = REZ.getString( "unknown-prop.error", name ); | |||||
throw new TaskException( message ); | |||||
} | |||||
/** | |||||
* Retrieve a copy of all the properties that are "in-scope" | |||||
* for store. | |||||
* | |||||
* @return a copy of all the properties that are "in-scope" | |||||
* for store. | |||||
* @throws TaskException if theres an error retrieving propertys | |||||
*/ | |||||
public Map getProperties() | |||||
throws TaskException | |||||
{ | |||||
final Map properties = new HashMap(); | |||||
if( m_parent != null ) | |||||
{ | |||||
properties.putAll( m_parent.getProperties() ); | |||||
} | |||||
properties.putAll( m_contextData ); | |||||
return properties; | |||||
} | |||||
/** | |||||
* Return a child PropertyStore with specified name. | |||||
* This is to allow support for scoped stores. However a | |||||
* store may choose to be unscoped and just return a | |||||
* reference to itself. | |||||
* | |||||
* @param name the name of child store | |||||
* @return the child store | |||||
* @throws TaskException if theres an error creating child store | |||||
*/ | |||||
public PropertyStore createChildStore( final String name ) | |||||
throws TaskException | |||||
{ | |||||
// Build the name for the new store | |||||
final String thisName = (String)m_contextData.get( TaskContext.NAME ); | |||||
final String newName; | |||||
if( name == null || name.length() == 0 ) | |||||
{ | |||||
newName = thisName; | |||||
} | |||||
else if( thisName.length() == 0 ) | |||||
{ | |||||
newName = name; | |||||
} | |||||
else | |||||
{ | |||||
newName = thisName + "." + name; | |||||
} | |||||
return new DefaultPropertyStore( newName, this, m_validator ); | |||||
} | |||||
/** | |||||
* Checks that the supplied property name is valid. | |||||
*/ | |||||
private void checkPropertyName( final String name ) | |||||
throws TaskException | |||||
{ | |||||
try | |||||
{ | |||||
m_validator.validate( name ); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
String message = REZ.getString( "bad-property-name.error", name ); | |||||
throw new TaskException( message, e ); | |||||
} | |||||
} | |||||
/** | |||||
* Make sure property is valid if it is one of the "magic" properties. | |||||
* | |||||
* @param name the name of property | |||||
* @param value the value of proeprty | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
private void checkPropertyValid( final String name, final Object value ) | |||||
throws TaskException | |||||
{ | |||||
if( TaskContext.BASE_DIRECTORY.equals( name ) && !( value instanceof File ) ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "bad-property.error", | |||||
TaskContext.BASE_DIRECTORY, | |||||
File.class.getName() ); | |||||
throw new TaskException( message ); | |||||
} | |||||
else if( TaskContext.NAME.equals( name ) && !( value instanceof String ) ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "bad-property.error", | |||||
TaskContext.NAME, | |||||
String.class.getName() ); | |||||
throw new TaskException( message ); | |||||
} | |||||
} | |||||
/** | |||||
* Create an instance of the default the name validator. | |||||
* | |||||
* @return the default NameValidator | |||||
*/ | |||||
private static NameValidator createDefaultNameValidator() | |||||
{ | |||||
final DefaultNameValidator defaultValidator = new DefaultNameValidator(); | |||||
defaultValidator.setAllowInternalWhitespace( false ); | |||||
defaultValidator.setAdditionalInternalCharacters( "_-.+" ); | |||||
return defaultValidator; | |||||
} | |||||
} |
@@ -1,5 +0,0 @@ | |||||
unknown-prop.error=Unknown property "{0}". | |||||
bad-property.error=Property "{0}" must have a value of type {1}. | |||||
bad-property-name.error=Invalid property name "{0}". | |||||
null-resolved-value.error=Value "{0}" resolved to null. | |||||
bad-resolve.error=Unable to resolve value "{0}". |
@@ -1,139 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.type; | |||||
import java.util.HashMap; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.avalon.framework.service.Serviceable; | |||||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
import org.apache.myrmidon.interfaces.type.TypeException; | |||||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
/** | |||||
* The interface that is used to manage types. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultTypeManager | |||||
implements TypeManager, Serviceable | |||||
{ | |||||
private static final Resources REZ | |||||
= ResourceManager.getPackageResources( DefaultTypeManager.class ); | |||||
///Parent type manager to inherit values from. | |||||
private final DefaultTypeManager m_parent; | |||||
///Maps role Class to MultiSourceTypeFactory. | |||||
private final HashMap m_roleMap = new HashMap(); | |||||
private RoleManager m_roleManager; | |||||
public DefaultTypeManager() | |||||
{ | |||||
this( null ); | |||||
} | |||||
private DefaultTypeManager( final DefaultTypeManager parent ) | |||||
{ | |||||
m_parent = parent; | |||||
if( m_parent != null ) | |||||
{ | |||||
m_roleManager = m_parent.m_roleManager; | |||||
} | |||||
} | |||||
public void service( final ServiceManager serviceManager ) | |||||
throws ServiceException | |||||
{ | |||||
m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||||
} | |||||
public void registerType( final String roleName, | |||||
final String shorthandName, | |||||
final TypeFactory factory ) | |||||
throws TypeException | |||||
{ | |||||
final MultiSourceTypeFactory msFactory = createFactory( roleName ); | |||||
msFactory.register( shorthandName, factory ); | |||||
} | |||||
public TypeFactory getFactory( final String roleName ) | |||||
throws TypeException | |||||
{ | |||||
return createFactory( roleName ); | |||||
} | |||||
public TypeManager createChildTypeManager() | |||||
{ | |||||
return new DefaultTypeManager( this ); | |||||
} | |||||
private final MultiSourceTypeFactory lookupFactory( final String roleName ) | |||||
{ | |||||
return (MultiSourceTypeFactory)m_roleMap.get( roleName ); | |||||
} | |||||
/** | |||||
* Get a factory of appropriate role. | |||||
* Create a Factory if none exists with same name. | |||||
* | |||||
* @param roleName the role name | |||||
* @return the Factory for interface | |||||
* @exception TypeException role does not specify accessible work interface | |||||
*/ | |||||
private MultiSourceTypeFactory createFactory( final String roleName ) | |||||
throws TypeException | |||||
{ | |||||
MultiSourceTypeFactory factory = (MultiSourceTypeFactory)m_roleMap.get( roleName ); | |||||
if( null != factory ) | |||||
{ | |||||
return factory; | |||||
} | |||||
final MultiSourceTypeFactory parentFactory = getParentTypedFactory( roleName ); | |||||
if( null != parentFactory ) | |||||
{ | |||||
factory = new MultiSourceTypeFactory( parentFactory ); | |||||
} | |||||
///If we haven't got factory try to create a new one | |||||
if( null == factory ) | |||||
{ | |||||
// Lookup the role type | |||||
final RoleInfo role = m_roleManager.getRole( roleName ); | |||||
if( role == null ) | |||||
{ | |||||
final String message = REZ.getString( "unknown-role.error", roleName ); | |||||
throw new TypeException( message ); | |||||
} | |||||
factory = new MultiSourceTypeFactory( role.getType() ); | |||||
} | |||||
m_roleMap.put( roleName, factory ); | |||||
return factory; | |||||
} | |||||
private MultiSourceTypeFactory getParentTypedFactory( final String roleName ) | |||||
{ | |||||
if( null != m_parent ) | |||||
{ | |||||
return m_parent.lookupFactory( roleName ); | |||||
} | |||||
else | |||||
{ | |||||
return null; | |||||
} | |||||
} | |||||
} |
@@ -1,124 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.type; | |||||
import java.util.HashMap; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.myrmidon.interfaces.type.TypeException; | |||||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||||
/** | |||||
* This factory acts as a proxy to set of object factories. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class MultiSourceTypeFactory | |||||
implements TypeFactory | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( MultiSourceTypeFactory.class ); | |||||
///Parent Selector | |||||
private final MultiSourceTypeFactory m_parent; | |||||
///Map of name->factory list | |||||
private final HashMap m_factories = new HashMap(); | |||||
///Type expected to be created from factories | |||||
private final Class m_type; | |||||
public MultiSourceTypeFactory( final Class type ) | |||||
{ | |||||
m_type = type; | |||||
m_parent = null; | |||||
} | |||||
public MultiSourceTypeFactory( final MultiSourceTypeFactory parent ) | |||||
{ | |||||
m_type = parent.getType(); | |||||
m_parent = parent; | |||||
} | |||||
/** | |||||
* Populate the ComponentSelector. | |||||
*/ | |||||
public void register( final String name, final TypeFactory factory ) | |||||
{ | |||||
m_factories.put( name, factory ); | |||||
} | |||||
/** | |||||
* Determines if this factory can create instances of a particular type. | |||||
*/ | |||||
public boolean canCreate( final String name ) | |||||
{ | |||||
return ( findFactory( name ) != null ); | |||||
} | |||||
/** | |||||
* Create a type instance based on name. | |||||
* | |||||
* @param name the name | |||||
* @return the type instance | |||||
* @exception TypeException if an error occurs | |||||
*/ | |||||
public Object create( final String name ) | |||||
throws TypeException | |||||
{ | |||||
// Locate the factory to use | |||||
TypeFactory factory = findFactory( name ); | |||||
if( null == factory ) | |||||
{ | |||||
final String message = REZ.getString( "no-factory.error", name ); | |||||
throw new TypeException( message ); | |||||
} | |||||
// Create the object | |||||
final Object object = factory.create( name ); | |||||
if( m_type != null && !m_type.isInstance( object ) ) | |||||
{ | |||||
final String message = REZ.getString( "mismatched-type.error", | |||||
name, object.getClass().getName() ); | |||||
throw new TypeException( message ); | |||||
} | |||||
return object; | |||||
} | |||||
/** | |||||
* Locates the type factory to use for a particular type. | |||||
*/ | |||||
private TypeFactory findFactory( final String name ) | |||||
{ | |||||
TypeFactory factory = getTypeFactory( name ); | |||||
if( null == factory && null != m_parent ) | |||||
{ | |||||
factory = m_parent.getTypeFactory( name ); | |||||
} | |||||
return factory; | |||||
} | |||||
/** | |||||
* Retrieve type managed by selector. | |||||
* Used by other instances of TypedComponentSelector. | |||||
* | |||||
* @return the type class | |||||
*/ | |||||
private final Class getType() | |||||
{ | |||||
return m_type; | |||||
} | |||||
private final TypeFactory getTypeFactory( final String name ) | |||||
{ | |||||
return (TypeFactory)m_factories.get( name ); | |||||
} | |||||
} |
@@ -1,9 +0,0 @@ | |||||
# DefaultTypeManager | |||||
unknown-role.error=Cannot create a type factory for unknown role {0}. | |||||
# MultiSourceTypeFactory | |||||
no-instantiate.error=Unable to instantiate ({0}). | |||||
no-mapping.error=Malconfigured factory, no classname for ({0}). | |||||
no-factory.error=Failed to locate factory for {0}. | |||||
mismatched-type.error=Factory for type {0} created an object of incompatible type {1}. | |||||
no-work-interface.error=Role {0} does not specify accessible work interface. |
@@ -1,61 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.workspace; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
/** | |||||
* Frames in which tasks are executed. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultExecutionFrame | |||||
implements ExecutionFrame | |||||
{ | |||||
private final Logger m_logger; | |||||
private final PropertyStore m_propertyStore; | |||||
private final ServiceManager m_serviceManager; | |||||
public DefaultExecutionFrame( final Logger logger, | |||||
final PropertyStore propertyStore, | |||||
final ServiceManager serviceManager ) | |||||
{ | |||||
m_logger = logger; | |||||
m_propertyStore = propertyStore; | |||||
m_serviceManager = serviceManager; | |||||
} | |||||
/** | |||||
* Returns the logger which is to be supplied to tasks. | |||||
*/ | |||||
public Logger getLogger() | |||||
{ | |||||
return m_logger; | |||||
} | |||||
/** | |||||
* Returns the set of services to use to create, configure, and execute | |||||
* tasks. | |||||
*/ | |||||
public ServiceManager getServiceManager() | |||||
{ | |||||
return m_serviceManager; | |||||
} | |||||
/** | |||||
* Returns the set of properties to be supplied to tasks. | |||||
*/ | |||||
public PropertyStore getProperties() | |||||
{ | |||||
return m_propertyStore; | |||||
} | |||||
} |
@@ -1,382 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.workspace; | |||||
import java.io.File; | |||||
import java.util.Map; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.excalibur.io.FileUtil; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
/** | |||||
* Default implementation of TaskContext. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultTaskContext | |||||
implements TaskContext | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultTaskContext.class ); | |||||
private final ServiceManager m_serviceManager; | |||||
private final Logger m_logger; | |||||
private final PropertyStore m_store; | |||||
private PropertyResolver m_propertyResolver; | |||||
/** | |||||
* Constructor that takes both parent context and a service directory. | |||||
*/ | |||||
public DefaultTaskContext( final ServiceManager serviceManager, | |||||
final Logger logger, | |||||
final PropertyStore store ) | |||||
{ | |||||
m_serviceManager = serviceManager; | |||||
m_logger = logger; | |||||
m_store = store; | |||||
if( null == m_serviceManager ) | |||||
{ | |||||
throw new NullPointerException( "serviceManager" ); | |||||
} | |||||
if( null == m_logger ) | |||||
{ | |||||
throw new NullPointerException( "logger" ); | |||||
} | |||||
if( null == m_store ) | |||||
{ | |||||
throw new NullPointerException( "store" ); | |||||
} | |||||
} | |||||
/** | |||||
* Retrieve Name of task. | |||||
* | |||||
* @return the name | |||||
*/ | |||||
public String getName() | |||||
{ | |||||
return (String)getProperty( NAME ); | |||||
} | |||||
/** | |||||
* Retrieve base directory. | |||||
* | |||||
* @return the base directory | |||||
*/ | |||||
public File getBaseDirectory() | |||||
{ | |||||
return (File)getProperty( BASE_DIRECTORY ); | |||||
} | |||||
/** | |||||
* Retrieve a service that is offered by the runtime. | |||||
* The actual services registered and in place for the | |||||
* task is determined by the container. The returned service | |||||
* <b>MUST</b> implement the specified interface. | |||||
* | |||||
* @param serviceClass the interface class that defines the service | |||||
* @return an instance of the service implementing interface specified by parameter | |||||
* @exception TaskException is thrown when the service is unavailable or not supported | |||||
*/ | |||||
public Object getService( final Class serviceClass ) | |||||
throws TaskException | |||||
{ | |||||
final String name = serviceClass.getName(); | |||||
//Note that this will chain up to parent ServiceManagers (if any) | |||||
if( null != m_serviceManager && m_serviceManager.hasService( name ) ) | |||||
{ | |||||
try | |||||
{ | |||||
return m_serviceManager.lookup( name ); | |||||
} | |||||
catch( final ServiceException se ) | |||||
{ | |||||
throw new TaskException( se.getMessage(), se ); | |||||
} | |||||
} | |||||
// Not found | |||||
final String message = REZ.getString( "bad-find-service.error", name ); | |||||
throw new TaskException( message ); | |||||
} | |||||
/** | |||||
* Resolve filename. | |||||
* This involves resolving it against baseDirectory and | |||||
* removing ../ and ./ references. It also means formatting | |||||
* it appropriately for the particular OS (ie different OS have | |||||
* different volumes, file conventions etc) | |||||
* | |||||
* @param filename the filename to resolve | |||||
* @return the resolved filename | |||||
*/ | |||||
public File resolveFile( final String filename ) | |||||
{ | |||||
return FileUtil.resolveFile( getBaseDirectory(), filename ); | |||||
} | |||||
/** | |||||
* Resolve a value according to the context. | |||||
* This involves evaluating the string and thus removing | |||||
* ${} sequences according to the rules specified at | |||||
* ............ | |||||
* | |||||
* @param value the value to resolve | |||||
* @return the resolved value | |||||
*/ | |||||
public Object resolveValue( final String value ) | |||||
throws TaskException | |||||
{ | |||||
try | |||||
{ | |||||
if( null == m_propertyResolver ) | |||||
{ | |||||
m_propertyResolver = (PropertyResolver)getService( PropertyResolver.class ); | |||||
} | |||||
final Object object = | |||||
m_propertyResolver.resolveProperties( value, this ); | |||||
if( null == object ) | |||||
{ | |||||
final String message = REZ.getString( "null-resolved-value.error", value ); | |||||
throw new TaskException( message ); | |||||
} | |||||
return object; | |||||
} | |||||
catch( final TaskException te ) | |||||
{ | |||||
final String message = REZ.getString( "bad-resolve.error", value ); | |||||
throw new TaskException( message, te ); | |||||
} | |||||
} | |||||
/** | |||||
* Retrieve property for name. | |||||
* | |||||
* @param name the name of property | |||||
* @return the value of the property | |||||
*/ | |||||
public Object getProperty( final String name ) | |||||
{ | |||||
try | |||||
{ | |||||
return m_store.getProperty( name ); | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* Retrieve a copy of all the properties accessible via context. | |||||
* | |||||
* @return the map of all property names to values | |||||
*/ | |||||
public Map getProperties() | |||||
throws TaskException | |||||
{ | |||||
return m_store.getProperties(); | |||||
} | |||||
/** | |||||
* Set property value in current context. | |||||
* | |||||
* @param name the name of property | |||||
* @param value the value of property | |||||
*/ | |||||
public void setProperty( final String name, final Object value ) | |||||
throws TaskException | |||||
{ | |||||
m_store.setProperty( name, value ); | |||||
} | |||||
/** | |||||
* Log a debug message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void debug( final String message ) | |||||
{ | |||||
m_logger.debug( message ); | |||||
} | |||||
/** | |||||
* Log a debug message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void debug( final String message, final Throwable throwable ) | |||||
{ | |||||
m_logger.debug( message, throwable ); | |||||
} | |||||
/** | |||||
* Determine if messages of priority "debug" will be logged. | |||||
* | |||||
* @return true if "debug" messages will be logged | |||||
*/ | |||||
public boolean isDebugEnabled() | |||||
{ | |||||
return m_logger.isDebugEnabled(); | |||||
} | |||||
/** | |||||
* Log a verbose message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void verbose( String message ) | |||||
{ | |||||
m_logger.info( message ); | |||||
} | |||||
/** | |||||
* Log a verbose message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void verbose( String message, Throwable throwable ) | |||||
{ | |||||
m_logger.info( message, throwable ); | |||||
} | |||||
/** | |||||
* Determine if messages of priority "verbose" will be logged. | |||||
* | |||||
* @return true if "verbose" messages will be logged | |||||
*/ | |||||
public boolean isVerboseEnabled() | |||||
{ | |||||
return m_logger.isInfoEnabled(); | |||||
} | |||||
/** | |||||
* Log a info message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void info( final String message ) | |||||
{ | |||||
m_logger.warn( message ); | |||||
} | |||||
/** | |||||
* Log a info message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void info( final String message, final Throwable throwable ) | |||||
{ | |||||
m_logger.warn( message, throwable ); | |||||
} | |||||
/** | |||||
* Determine if messages of priority "info" will be logged. | |||||
* | |||||
* @return true if "info" messages will be logged | |||||
*/ | |||||
public boolean isInfoEnabled() | |||||
{ | |||||
return m_logger.isWarnEnabled(); | |||||
} | |||||
/** | |||||
* Log a warn message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void warn( final String message ) | |||||
{ | |||||
m_logger.error( message ); | |||||
} | |||||
/** | |||||
* Log a warn message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void warn( final String message, final Throwable throwable ) | |||||
{ | |||||
m_logger.error( message, throwable ); | |||||
} | |||||
/** | |||||
* Determine if messages of priority "warn" will be logged. | |||||
* | |||||
* @return true if "warn" messages will be logged | |||||
*/ | |||||
public boolean isWarnEnabled() | |||||
{ | |||||
return m_logger.isErrorEnabled(); | |||||
} | |||||
/** | |||||
* Log a error message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void error( final String message ) | |||||
{ | |||||
m_logger.fatalError( message ); | |||||
} | |||||
/** | |||||
* Log a error message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void error( final String message, final Throwable throwable ) | |||||
{ | |||||
m_logger.fatalError( message, throwable ); | |||||
} | |||||
/** | |||||
* Determine if messages of priority "error" will be logged. | |||||
* | |||||
* @return true if "error" messages will be logged | |||||
*/ | |||||
public boolean isErrorEnabled() | |||||
{ | |||||
return m_logger.isFatalErrorEnabled(); | |||||
} | |||||
/** | |||||
* Create a Child Context. | |||||
* This allows separate hierarchly contexts to be easily constructed. | |||||
* | |||||
* @param name the name of sub-context | |||||
* @return the created TaskContext | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
public TaskContext createSubContext( final String name ) | |||||
throws TaskException | |||||
{ | |||||
final PropertyStore store = m_store.createChildStore( name ); | |||||
final DefaultServiceManager serviceManager = | |||||
new DefaultServiceManager( m_serviceManager ); | |||||
final Logger logger = m_logger.getChildLogger( name ); | |||||
return new DefaultTaskContext( serviceManager, logger, store ); | |||||
} | |||||
} |
@@ -1,437 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.workspace; | |||||
import java.io.File; | |||||
import java.util.HashMap; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.context.Context; | |||||
import org.apache.avalon.framework.context.ContextException; | |||||
import org.apache.avalon.framework.context.Contextualizable; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.interfaces.deployer.Deployer; | |||||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||||
import org.apache.myrmidon.interfaces.executor.ExecutionContainer; | |||||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
import org.apache.myrmidon.interfaces.executor.Executor; | |||||
import org.apache.myrmidon.interfaces.model.Dependency; | |||||
import org.apache.myrmidon.interfaces.model.Project; | |||||
import org.apache.myrmidon.interfaces.model.Target; | |||||
import org.apache.myrmidon.interfaces.model.TypeLib; | |||||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||||
import org.apache.myrmidon.listeners.ProjectListener; | |||||
/** | |||||
* This is the default implementation of Workspace. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultWorkspace | |||||
extends AbstractLogEnabled | |||||
implements Workspace, ExecutionContainer, Contextualizable | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultWorkspace.class ); | |||||
private Executor m_executor; | |||||
private ProjectListenerSupport m_listenerSupport = new ProjectListenerSupport(); | |||||
private ServiceManager m_serviceManager; | |||||
private PropertyStore m_baseStore; | |||||
private TypeManager m_typeManager; | |||||
private Deployer m_deployer; | |||||
private Context m_context; | |||||
/** A map from Project object -> ProjectEntry for that project. */ | |||||
private HashMap m_entries = new HashMap(); | |||||
/** | |||||
* Add a listener to project events. | |||||
* | |||||
* @param listener the listener | |||||
*/ | |||||
public void addProjectListener( final ProjectListener listener ) | |||||
{ | |||||
m_listenerSupport.addProjectListener( listener ); | |||||
} | |||||
/** | |||||
* Remove a listener from project events. | |||||
* | |||||
* @param listener the listener | |||||
*/ | |||||
public void removeProjectListener( final ProjectListener listener ) | |||||
{ | |||||
m_listenerSupport.removeProjectListener( listener ); | |||||
} | |||||
/** | |||||
* Sets the root execution frame. | |||||
*/ | |||||
public void setRootExecutionFrame( final ExecutionFrame frame ) throws Exception | |||||
{ | |||||
m_baseStore = frame.getProperties(); | |||||
m_serviceManager = frame.getServiceManager(); | |||||
m_typeManager = (TypeManager)m_serviceManager.lookup( TypeManager.ROLE ); | |||||
m_executor = (Executor)m_serviceManager.lookup( Executor.ROLE ); | |||||
m_deployer = (Deployer)m_serviceManager.lookup( Deployer.ROLE ); | |||||
} | |||||
public void contextualize( final Context context ) throws ContextException | |||||
{ | |||||
m_context = context; | |||||
} | |||||
/** | |||||
* Execute a target in a particular project. | |||||
* Execute in the project context. | |||||
* | |||||
* @param project the Project | |||||
* @param target the name of the target | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
public void executeProject( final Project project, final String target ) | |||||
throws TaskException | |||||
{ | |||||
final ProjectEntry entry = getProjectEntry( project ); | |||||
m_listenerSupport.projectStarted( project.getProjectName() ); | |||||
executeTarget( entry, target ); | |||||
m_listenerSupport.projectFinished( project.getProjectName() ); | |||||
} | |||||
private File findTypeLib( final String libraryName ) | |||||
throws Exception | |||||
{ | |||||
//TODO: In future this will be expanded to allow | |||||
//users to specify search path or automagically | |||||
//add entries to lib path (like user specific or | |||||
//workspace specific) | |||||
final String name = libraryName.replace( '/', File.separatorChar ) + ".atl"; | |||||
final File[] extPath = (File[])m_context.get( "myrmidon.antlib.path" ); | |||||
for( int i = 0; i < extPath.length; i++ ) | |||||
{ | |||||
final File extDir = extPath[ i ]; | |||||
final File library = new File( extDir, name ); | |||||
if( library.exists() ) | |||||
{ | |||||
if( !library.canRead() ) | |||||
{ | |||||
final String message = REZ.getString( "no-read.error", library ); | |||||
throw new TaskException( message ); | |||||
} | |||||
else | |||||
{ | |||||
return library; | |||||
} | |||||
} | |||||
} | |||||
final String message = REZ.getString( "no-library.error", libraryName ); | |||||
throw new TaskException( message ); | |||||
} | |||||
private void deployTypeLib( final Deployer deployer, final Project project ) | |||||
throws Exception | |||||
{ | |||||
final TypeLib[] typeLibs = project.getTypeLibs(); | |||||
for( int i = 0; i < typeLibs.length; i++ ) | |||||
{ | |||||
final TypeLib typeLib = typeLibs[ i ]; | |||||
final File file = findTypeLib( typeLib.getLibrary() ); | |||||
try | |||||
{ | |||||
final TypeDeployer typeDeployer = deployer.createDeployer( file ); | |||||
if( null == typeLib.getRole() ) | |||||
{ | |||||
// Deploy everything in the typelib | |||||
typeDeployer.deployAll(); | |||||
} | |||||
else | |||||
{ | |||||
// Deploy the specified type | |||||
typeDeployer.deployType( typeLib.getRole(), typeLib.getName() ); | |||||
} | |||||
} | |||||
catch( final DeploymentException de ) | |||||
{ | |||||
final String message = REZ.getString( "no-deploy.error", | |||||
typeLib.getLibrary(), file ); | |||||
throw new TaskException( message, de ); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Creates an execution frame for a project. | |||||
*/ | |||||
private ExecutionFrame createExecutionFrame( final Project project ) | |||||
throws Exception | |||||
{ | |||||
//Create per frame ComponentManager | |||||
final DefaultServiceManager serviceManager = | |||||
new DefaultServiceManager( m_serviceManager ); | |||||
//Add in child type manager so each frame can register different | |||||
//sets of tasks etc | |||||
final TypeManager typeManager = m_typeManager.createChildTypeManager(); | |||||
serviceManager.put( TypeManager.ROLE, typeManager ); | |||||
// TODO - Add child role manager and configurer | |||||
//We need to create a new deployer so that it deploys | |||||
//to project specific TypeManager | |||||
final Deployer deployer = m_deployer.createChildDeployer( serviceManager ); | |||||
serviceManager.put( Deployer.ROLE, deployer ); | |||||
// Deploy the imported typelibs | |||||
deployTypeLib( deployer, project ); | |||||
//We need to place projects and ProjectManager | |||||
//in ComponentManager so as to support project-local call() | |||||
// TODO - add project to properties, not services | |||||
serviceManager.put( Workspace.ROLE, this ); | |||||
serviceManager.put( Project.ROLE, project ); | |||||
// Create a logger | |||||
final Logger logger = | |||||
new RoutingLogger( getLogger(), m_listenerSupport ); | |||||
// Properties | |||||
final PropertyStore store = m_baseStore.createChildStore(""); | |||||
store.setProperty( TaskContext.BASE_DIRECTORY, project.getBaseDirectory() ); | |||||
final DefaultExecutionFrame frame = | |||||
new DefaultExecutionFrame( logger, store, serviceManager ); | |||||
/** | |||||
* @todo Should no occur but done for the time being to simplify evolution. | |||||
*/ | |||||
serviceManager.put( ExecutionFrame.ROLE, frame ); | |||||
return frame; | |||||
} | |||||
private ProjectEntry getProjectEntry( final Project project ) | |||||
throws TaskException | |||||
{ | |||||
ProjectEntry entry = (ProjectEntry)m_entries.get( project ); | |||||
if( null == entry ) | |||||
{ | |||||
try | |||||
{ | |||||
final ExecutionFrame frame = createExecutionFrame( project ); | |||||
entry = new ProjectEntry( project, frame ); | |||||
m_entries.put( project, entry ); | |||||
} | |||||
catch( Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "bad-frame.error" ); | |||||
throw new TaskException( message, e ); | |||||
} | |||||
} | |||||
return entry; | |||||
} | |||||
private Project getProject( final String name, final Project project ) | |||||
throws TaskException | |||||
{ | |||||
final Project other = project.getProject( name ); | |||||
if( null == other ) | |||||
{ | |||||
//TODO: Fix this so location information included in description | |||||
final String message = REZ.getString( "no-project.error", name ); | |||||
throw new TaskException( message ); | |||||
} | |||||
return other; | |||||
} | |||||
/** | |||||
* Helper method to execute a target. | |||||
* | |||||
* @param entry the project to execute | |||||
* @param targetName the name of the target to execute | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
private void executeTarget( final ProjectEntry entry, | |||||
final String targetName ) | |||||
throws TaskException | |||||
{ | |||||
// Locate the target | |||||
final Target target = entry.getProject().getTarget( targetName ); | |||||
if( null == target ) | |||||
{ | |||||
final String message = REZ.getString( "no-target.error", targetName ); | |||||
throw new TaskException( message ); | |||||
} | |||||
executeTarget( entry, targetName, target ); | |||||
} | |||||
/** | |||||
* Executes a target. Does not execute the target if it has already been | |||||
* executed. Executes the dependencies of the target, before executing | |||||
* the target itself. | |||||
* | |||||
* @param name the name of target | |||||
* @param target the target | |||||
* @param entry the project in which to execute | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
private void executeTarget( final ProjectEntry entry, | |||||
final String name, | |||||
final Target target ) | |||||
throws TaskException | |||||
{ | |||||
final Project project = entry.getProject(); | |||||
// Check target state, to see if it has already been executed, and | |||||
// to check for dependency cycles | |||||
final TargetState state = entry.getTargetState( target ); | |||||
if( state == TargetState.FINISHED ) | |||||
{ | |||||
// Target has been executed | |||||
return; | |||||
} | |||||
if( state == TargetState.TRAVERSING ) | |||||
{ | |||||
// Cycle in target dependencies | |||||
final String message = REZ.getString( "target-dependency-cycle.error", name ); | |||||
throw new TaskException( message ); | |||||
} | |||||
// Set state to indicate this target has been started | |||||
entry.setTargetState( target, TargetState.TRAVERSING ); | |||||
// Execute the target's dependencies | |||||
// Implicit target first | |||||
if( target != project.getImplicitTarget() ) | |||||
{ | |||||
executeTarget( entry, "<init>", project.getImplicitTarget() ); | |||||
} | |||||
// Named dependencies | |||||
final Dependency[] dependencies = target.getDependencies(); | |||||
for( int i = 0; i < dependencies.length; i++ ) | |||||
{ | |||||
final Dependency dependency = dependencies[ i ]; | |||||
final String otherProjectName = dependency.getProjectName(); | |||||
if( otherProjectName != null ) | |||||
{ | |||||
// Dependency in a referenced project | |||||
final Project otherProject = getProject( otherProjectName, project ); | |||||
final ProjectEntry otherEntry = getProjectEntry( otherProject ); | |||||
executeTarget( otherEntry, dependency.getTargetName() ); | |||||
} | |||||
else | |||||
{ | |||||
// Dependency in this project | |||||
executeTarget( entry, dependency.getTargetName() ); | |||||
} | |||||
} | |||||
// Now execute the target itself | |||||
executeTargetNoDeps( entry, name, target ); | |||||
// Mark target as complete | |||||
entry.setTargetState( target, TargetState.FINISHED ); | |||||
} | |||||
/** | |||||
* Executes a target. Does not check whether the target has been | |||||
* executed already, and does not check that its dependencies have been | |||||
* executed. | |||||
* | |||||
* @param entry the project to execute the target in. | |||||
* @param name the name of the target. | |||||
* @param target the target itself | |||||
*/ | |||||
private void executeTargetNoDeps( final ProjectEntry entry, | |||||
final String name, | |||||
final Target target ) | |||||
throws TaskException | |||||
{ | |||||
final Project project = entry.getProject(); | |||||
// Notify listeners | |||||
m_listenerSupport.targetStarted( project.getProjectName(), name ); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( "exec-target.notice", | |||||
project.getProjectName(), name ); | |||||
getLogger().debug( message ); | |||||
} | |||||
//TODO - put this back in | |||||
//frame.getContext().setProperty( Project.TARGET, target ); | |||||
// Execute all tasks assciated with target | |||||
final Configuration[] tasks = target.getTasks(); | |||||
for( int i = 0; i < tasks.length; i++ ) | |||||
{ | |||||
executeTask( tasks[ i ], entry.getFrame() ); | |||||
} | |||||
// Notify listeners | |||||
m_listenerSupport.targetFinished(); | |||||
} | |||||
/** | |||||
* Execute a task. | |||||
* | |||||
* @param task the task definition | |||||
* @param frame the frame to execute in | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
private void executeTask( final Configuration task, final ExecutionFrame frame ) | |||||
throws TaskException | |||||
{ | |||||
final String name = task.getName(); | |||||
if( getLogger().isDebugEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( "exec-task.notice", name ); | |||||
getLogger().debug( message ); | |||||
} | |||||
//is setting name even necessary ??? | |||||
frame.getProperties().setProperty( TaskContext.NAME, name ); | |||||
//notify listeners | |||||
m_listenerSupport.taskStarted( name ); | |||||
//run task | |||||
m_executor.execute( task, frame ); | |||||
//notify listeners task has ended | |||||
m_listenerSupport.taskFinished(); | |||||
} | |||||
} |
@@ -1,62 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.workspace; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||||
import org.apache.myrmidon.interfaces.model.Project; | |||||
import org.apache.myrmidon.interfaces.model.Target; | |||||
/** | |||||
* This contains details for each project that is being executed by a | |||||
* DefaultWorkspace. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
final class ProjectEntry | |||||
{ | |||||
private final Project m_project; | |||||
private final ExecutionFrame m_frame; | |||||
/** Map from Target -> TargetState for that target. */ | |||||
private final Map m_targetState = new HashMap(); | |||||
public ProjectEntry( final Project project, | |||||
final ExecutionFrame frame ) | |||||
{ | |||||
m_project = project; | |||||
m_frame = frame; | |||||
} | |||||
public Project getProject() | |||||
{ | |||||
return m_project; | |||||
} | |||||
public ExecutionFrame getFrame() | |||||
{ | |||||
return m_frame; | |||||
} | |||||
public TargetState getTargetState( final Target target ) | |||||
{ | |||||
TargetState state = (TargetState)m_targetState.get( target ); | |||||
if( state == null ) | |||||
{ | |||||
state = TargetState.NOT_STARTED; | |||||
} | |||||
return state; | |||||
} | |||||
public void setTargetState( final Target target, final TargetState state ) | |||||
{ | |||||
m_targetState.put( target, state ); | |||||
} | |||||
} |
@@ -1,224 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.workspace; | |||||
import org.apache.myrmidon.listeners.LogEvent; | |||||
import org.apache.myrmidon.listeners.ProjectListener; | |||||
/** | |||||
* Support for the project listener event dispatching. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
class ProjectListenerSupport | |||||
implements LogEvent | |||||
{ | |||||
private ProjectListener[] m_listeners = new ProjectListener[ 0 ]; | |||||
private String m_projectName; | |||||
private String m_targetName; | |||||
private String m_taskName; | |||||
private String m_message; | |||||
private Throwable m_throwable; | |||||
/** | |||||
* Add an extra project listener that wants to receive notification of listener events. | |||||
* | |||||
* @param listener the listener | |||||
*/ | |||||
public void addProjectListener( final ProjectListener listener ) | |||||
{ | |||||
final ProjectListener[] listeners = new ProjectListener[ m_listeners.length + 1 ]; | |||||
System.arraycopy( m_listeners, 0, listeners, 0, m_listeners.length ); | |||||
listeners[ m_listeners.length ] = listener; | |||||
m_listeners = listeners; | |||||
} | |||||
/** | |||||
* Remove a project listener that wants to receive notification of listener events. | |||||
* | |||||
* @param listener the listener | |||||
*/ | |||||
public void removeProjectListener( final ProjectListener listener ) | |||||
{ | |||||
int found = -1; | |||||
for( int i = 0; i < m_listeners.length; i++ ) | |||||
{ | |||||
if( listener == m_listeners[ i ] ) | |||||
{ | |||||
found = i; | |||||
break; | |||||
} | |||||
} | |||||
if( -1 == found ) | |||||
{ | |||||
return; | |||||
} | |||||
final ProjectListener[] listeners = new ProjectListener[ m_listeners.length - 1 ]; | |||||
System.arraycopy( m_listeners, 0, listeners, 0, found ); | |||||
final int count = m_listeners.length - found - 1; | |||||
System.arraycopy( m_listeners, found, listeners, found + 1, count ); | |||||
m_listeners = listeners; | |||||
} | |||||
/** | |||||
* Fire a projectStarted event. | |||||
*/ | |||||
public void projectStarted( final String projectName ) | |||||
{ | |||||
m_projectName = projectName; | |||||
m_targetName = null; | |||||
m_taskName = null; | |||||
for( int i = 0; i < m_listeners.length; i++ ) | |||||
{ | |||||
m_listeners[ i ].projectStarted( this ); | |||||
} | |||||
} | |||||
/** | |||||
* Fire a projectFinished event. | |||||
*/ | |||||
public void projectFinished( final String projectName ) | |||||
{ | |||||
m_projectName = projectName; | |||||
for( int i = 0; i < m_listeners.length; i++ ) | |||||
{ | |||||
m_listeners[ i ].projectFinished( this ); | |||||
} | |||||
m_projectName = null; | |||||
m_targetName = null; | |||||
m_taskName = null; | |||||
} | |||||
/** | |||||
* Fire a targetStarted event. | |||||
*/ | |||||
public void targetStarted( final String projectName, final String targetName ) | |||||
{ | |||||
m_projectName = projectName; | |||||
m_targetName = targetName; | |||||
m_taskName = null; | |||||
for( int i = 0; i < m_listeners.length; i++ ) | |||||
{ | |||||
m_listeners[ i ].targetStarted( this ); | |||||
} | |||||
} | |||||
/** | |||||
* Fire a targetFinished event. | |||||
*/ | |||||
public void targetFinished() | |||||
{ | |||||
for( int i = 0; i < m_listeners.length; i++ ) | |||||
{ | |||||
m_listeners[ i ].targetFinished( this ); | |||||
} | |||||
m_targetName = null; | |||||
m_taskName = null; | |||||
} | |||||
/** | |||||
* Fire a targetStarted event. | |||||
*/ | |||||
public void taskStarted( final String taskName ) | |||||
{ | |||||
m_taskName = taskName; | |||||
for( int i = 0; i < m_listeners.length; i++ ) | |||||
{ | |||||
m_listeners[ i ].taskStarted( this ); | |||||
} | |||||
} | |||||
/** | |||||
* Fire a taskFinished event. | |||||
*/ | |||||
public void taskFinished() | |||||
{ | |||||
for( int i = 0; i < m_listeners.length; i++ ) | |||||
{ | |||||
m_listeners[ i ].taskFinished( this ); | |||||
} | |||||
m_taskName = null; | |||||
} | |||||
/** | |||||
* Fire a log event. | |||||
* | |||||
* @param message the log message | |||||
*/ | |||||
public void log( String message, Throwable throwable ) | |||||
{ | |||||
m_message = message; | |||||
m_throwable = throwable; | |||||
try | |||||
{ | |||||
for( int i = 0; i < m_listeners.length; i++ ) | |||||
{ | |||||
m_listeners[ i ].log( this ); | |||||
} | |||||
} | |||||
finally | |||||
{ | |||||
m_message = null; | |||||
m_throwable = null; | |||||
} | |||||
} | |||||
/** | |||||
* Returns the message. | |||||
*/ | |||||
public String getMessage() | |||||
{ | |||||
return m_message; | |||||
} | |||||
/** | |||||
* Returns the error that occurred. | |||||
*/ | |||||
public Throwable getThrowable() | |||||
{ | |||||
return m_throwable; | |||||
} | |||||
/** | |||||
* Returns the name of the task. | |||||
*/ | |||||
public String getTaskName() | |||||
{ | |||||
return m_taskName; | |||||
} | |||||
/** | |||||
* Returns the name of the target. | |||||
*/ | |||||
public String getTargetName() | |||||
{ | |||||
return m_targetName; | |||||
} | |||||
/** | |||||
* Returns the name of the project. | |||||
*/ | |||||
public String getProjectName() | |||||
{ | |||||
return m_projectName; | |||||
} | |||||
} |
@@ -1,19 +0,0 @@ | |||||
no-read.error=Unable to read library at {0}. | |||||
no-library.error=Unable to locate Type Library {0}. | |||||
no-deploy.error=Error deploying type library {0} at {1}. | |||||
bad-deployer-config.error=Error configuring deployer. | |||||
bad-frame.error=Error setting up ExecutionFrame. | |||||
no-project.error=Project {0} not found. | |||||
no-target.error=Target {0} not found. | |||||
exec-target.notice=Executing project {0}, target {1}. | |||||
exec-task.notice=Executing task {0}. | |||||
target-dependency-cycle.error=Cycle in dependencies for target {0}. | |||||
#DefaultTaskContext | |||||
unknown-prop.error=Unknown property {0}. | |||||
bad-property.error=Property {0} must have a value of type {1}. | |||||
bad-property-name.error=Invalid property name. | |||||
null-resolved-value.error=Value "{0}" resolved to null. | |||||
bad-resolve.error=Unable to resolve value "{0}". | |||||
bad-find-service.error=Could not find service "{0}". | |||||
bad-service-class.error=Find service "{0}" but it was of type {1} where it was expected to be of type {2}. |
@@ -1,85 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.workspace; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
import org.apache.myrmidon.frontends.AbstractLogger; | |||||
/** | |||||
* A logger that just routes the messages to the ProjectListenerSupport. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
final class RoutingLogger | |||||
extends AbstractLogger | |||||
implements Logger | |||||
{ | |||||
/** | |||||
* The endpoint of all the logging messages. | |||||
*/ | |||||
private final ProjectListenerSupport m_listenerSupport; | |||||
/** | |||||
* A wrapped logger that is used to determine which message types are | |||||
* enabled. | |||||
*/ | |||||
private final Logger m_logger; | |||||
/** | |||||
* Create a Logger that routes messages at specified level | |||||
* to specified support. | |||||
* | |||||
* @todo Use something other than a logger to figure out which messages | |||||
* are enabled. | |||||
*/ | |||||
public RoutingLogger( final Logger logger, | |||||
final ProjectListenerSupport listenerSupport ) | |||||
{ | |||||
m_listenerSupport = listenerSupport; | |||||
m_logger = logger; | |||||
} | |||||
public boolean isDebugEnabled() | |||||
{ | |||||
return m_logger.isDebugEnabled(); | |||||
} | |||||
public boolean isInfoEnabled() | |||||
{ | |||||
return m_logger.isInfoEnabled(); | |||||
} | |||||
public boolean isWarnEnabled() | |||||
{ | |||||
return m_logger.isWarnEnabled(); | |||||
} | |||||
public boolean isErrorEnabled() | |||||
{ | |||||
return m_logger.isErrorEnabled(); | |||||
} | |||||
public boolean isFatalErrorEnabled() | |||||
{ | |||||
return m_logger.isFatalErrorEnabled(); | |||||
} | |||||
public Logger getChildLogger( final String name ) | |||||
{ | |||||
return new RoutingLogger( m_logger.getChildLogger( name ), m_listenerSupport ); | |||||
} | |||||
/** | |||||
* Utility method to output messages. | |||||
*/ | |||||
protected void output( final String message, final Throwable throwable ) | |||||
{ | |||||
m_listenerSupport.log( message, throwable ); | |||||
} | |||||
} |
@@ -1,34 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.components.workspace; | |||||
/** | |||||
* An enumerated type that represents the dependency traversal state of a | |||||
* target. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
final class TargetState | |||||
{ | |||||
private TargetState() | |||||
{ | |||||
} | |||||
/** Target has not been started. */ | |||||
public static final TargetState NOT_STARTED = new TargetState(); | |||||
/** | |||||
* Target has been started, and the dependencies of the target are being | |||||
* traversed. | |||||
*/ | |||||
public static final TargetState TRAVERSING = new TargetState(); | |||||
/** Target has been completed. */ | |||||
public static final TargetState FINISHED = new TargetState(); | |||||
} |
@@ -1,167 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.frontends; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
/** | |||||
* A partial logger implementation. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public abstract class AbstractLogger | |||||
implements Logger | |||||
{ | |||||
public static final int LEVEL_DEBUG = 0; | |||||
public static final int LEVEL_INFO = 1; | |||||
public static final int LEVEL_WARN = 2; | |||||
public static final int LEVEL_ERROR = 3; | |||||
public static final int LEVEL_FATAL = 4; | |||||
/** | |||||
* Log a debug message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void debug( final String message ) | |||||
{ | |||||
if( isDebugEnabled() ) | |||||
{ | |||||
output( message, null ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a debug message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void debug( final String message, final Throwable throwable ) | |||||
{ | |||||
if( isDebugEnabled() ) | |||||
{ | |||||
output( message, throwable ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a info message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void info( final String message ) | |||||
{ | |||||
if( isInfoEnabled() ) | |||||
{ | |||||
output( message, null ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a info message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void info( final String message, final Throwable throwable ) | |||||
{ | |||||
if( isInfoEnabled() ) | |||||
{ | |||||
output( message, throwable ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a warn message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void warn( final String message ) | |||||
{ | |||||
if( isWarnEnabled() ) | |||||
{ | |||||
output( message, null ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a warn message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void warn( final String message, final Throwable throwable ) | |||||
{ | |||||
if( isWarnEnabled() ) | |||||
{ | |||||
output( message, throwable ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a error message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void error( final String message ) | |||||
{ | |||||
if( isErrorEnabled() ) | |||||
{ | |||||
output( message, null ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a error message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void error( final String message, final Throwable throwable ) | |||||
{ | |||||
if( isErrorEnabled() ) | |||||
{ | |||||
output( message, throwable ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a fatalError message. | |||||
* | |||||
* @param message the message | |||||
*/ | |||||
public void fatalError( final String message ) | |||||
{ | |||||
if( isFatalErrorEnabled() ) | |||||
{ | |||||
output( message, null ); | |||||
} | |||||
} | |||||
/** | |||||
* Log a fatalError message. | |||||
* | |||||
* @param message the message | |||||
* @param throwable the throwable | |||||
*/ | |||||
public void fatalError( final String message, final Throwable throwable ) | |||||
{ | |||||
if( isFatalErrorEnabled() ) | |||||
{ | |||||
output( message, throwable ); | |||||
} | |||||
} | |||||
/** | |||||
* Utility method to output messages. | |||||
*/ | |||||
protected abstract void output( final String message, | |||||
final Throwable throwable ); | |||||
} |
@@ -1,124 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.frontends; | |||||
import org.apache.avalon.framework.ExceptionUtil; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
/** | |||||
* A basic logger that just prints out messages to <code>System.out</code>. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class BasicLogger | |||||
extends AbstractLogger | |||||
implements Logger | |||||
{ | |||||
/** | |||||
* The string prefixed to all log messages. | |||||
*/ | |||||
private final String m_prefix; | |||||
/** | |||||
* The level at which messages start becoming logged. | |||||
*/ | |||||
private final int m_logLevel; | |||||
/** | |||||
* Create a logger that has specified prefix and is logging | |||||
* at specified level. | |||||
*/ | |||||
public BasicLogger( final String prefix, final int logLevel ) | |||||
{ | |||||
m_prefix = prefix; | |||||
m_logLevel = logLevel; | |||||
} | |||||
/** | |||||
* Determine if messages of priority "debug" will be logged. | |||||
* | |||||
* @return true if "debug" messages will be logged | |||||
*/ | |||||
public boolean isDebugEnabled() | |||||
{ | |||||
return m_logLevel <= LEVEL_DEBUG; | |||||
} | |||||
/** | |||||
* Determine if messages of priority "info" will be logged. | |||||
* | |||||
* @return true if "info" messages will be logged | |||||
*/ | |||||
public boolean isInfoEnabled() | |||||
{ | |||||
return m_logLevel <= LEVEL_INFO; | |||||
} | |||||
/** | |||||
* Determine if messages of priority "warn" will be logged. | |||||
* | |||||
* @return true if "warn" messages will be logged | |||||
*/ | |||||
public boolean isWarnEnabled() | |||||
{ | |||||
return m_logLevel <= LEVEL_WARN; | |||||
} | |||||
/** | |||||
* Determine if messages of priority "error" will be logged. | |||||
* | |||||
* @return true if "error" messages will be logged | |||||
*/ | |||||
public boolean isErrorEnabled() | |||||
{ | |||||
return m_logLevel <= LEVEL_ERROR; | |||||
} | |||||
/** | |||||
* Determine if messages of priority "fatalError" will be logged. | |||||
* | |||||
* @return true if "fatalError" messages will be logged | |||||
*/ | |||||
public boolean isFatalErrorEnabled() | |||||
{ | |||||
return m_logLevel <= LEVEL_FATAL; | |||||
} | |||||
/** | |||||
* Create a new child logger. | |||||
* The name of the child logger is [current-loggers-name].[passed-in-name] | |||||
* | |||||
* @param name the subname of this logger | |||||
* @return the new logger | |||||
* @exception IllegalArgumentException if name has an empty element name | |||||
*/ | |||||
public Logger getChildLogger( final String name ) | |||||
{ | |||||
return new BasicLogger( m_prefix + "." + name, m_logLevel ); | |||||
} | |||||
/** | |||||
* Utility method to output messages. | |||||
*/ | |||||
protected void output( final String message, final Throwable throwable ) | |||||
{ | |||||
final StringBuffer sb = new StringBuffer( m_prefix ); | |||||
if( null != message ) | |||||
{ | |||||
sb.append( message ); | |||||
} | |||||
System.out.println( sb ); | |||||
if( null != throwable ) | |||||
{ | |||||
final String stackTrace = ExceptionUtil.printStackTrace( throwable, 8, true, true ); | |||||
System.out.println( stackTrace ); | |||||
} | |||||
} | |||||
} |
@@ -1,477 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.frontends; | |||||
import java.io.BufferedReader; | |||||
import java.io.File; | |||||
import java.io.InputStreamReader; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import org.apache.avalon.excalibur.cli.CLArgsParser; | |||||
import org.apache.avalon.excalibur.cli.CLOption; | |||||
import org.apache.avalon.excalibur.cli.CLOptionDescriptor; | |||||
import org.apache.avalon.excalibur.cli.CLUtil; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.framework.CascadingException; | |||||
import org.apache.avalon.framework.ExceptionUtil; | |||||
import org.apache.myrmidon.Constants; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.interfaces.executor.Executor; | |||||
/** | |||||
* The class to kick the tires and light the fires. | |||||
* Starts myrmidon, loads ProjectBuilder, builds project then uses ProjectManager | |||||
* to run project. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class CLIMain | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( CLIMain.class ); | |||||
//defines for the Command Line options | |||||
private static final int HELP_OPT = 'h'; | |||||
private static final int QUIET_OPT = 'q'; | |||||
private static final int VERBOSE_OPT = 'v'; | |||||
private static final int FILE_OPT = 'f'; | |||||
private static final int LOG_LEVEL_OPT = 'l'; | |||||
private static final int DEFINE_OPT = 'D'; | |||||
private static final int BUILDER_PARAM_OPT = 'B'; | |||||
private static final int NO_PREFIX_OPT = 'p'; | |||||
private static final int VERSION_OPT = 1; | |||||
private static final int LISTENER_OPT = 2; | |||||
private static final int TASKLIB_DIR_OPT = 5; | |||||
private static final int EXTLIB_DIR_OPT = 6; | |||||
private static final int INCREMENTAL_OPT = 7; | |||||
private static final int HOME_DIR_OPT = 8; | |||||
private static final int DRY_RUN_OPT = 9; | |||||
private static final int DEBUG_OPT = 10; | |||||
private static final int TYPE_OPT = 11; | |||||
//incompatable options for info options | |||||
private static final int[] INFO_OPT_INCOMPAT = new int[] | |||||
{ | |||||
HELP_OPT, QUIET_OPT, VERBOSE_OPT, FILE_OPT, | |||||
LOG_LEVEL_OPT, BUILDER_PARAM_OPT, NO_PREFIX_OPT, | |||||
VERSION_OPT, LISTENER_OPT, TASKLIB_DIR_OPT, EXTLIB_DIR_OPT, | |||||
INCREMENTAL_OPT, HOME_DIR_OPT, DRY_RUN_OPT, TYPE_OPT | |||||
}; | |||||
//incompatable options for other logging options | |||||
private static final int[] LOG_OPT_INCOMPAT = new int[] | |||||
{ | |||||
QUIET_OPT, VERBOSE_OPT, LOG_LEVEL_OPT, DEBUG_OPT | |||||
}; | |||||
//incompatible options for listener options | |||||
private static final int[] LISTENER_OPT_INCOMPAT = new int[] | |||||
{ | |||||
LISTENER_OPT, NO_PREFIX_OPT | |||||
}; | |||||
///List of targets supplied on command line to execute | |||||
private ArrayList m_targets = new ArrayList(); | |||||
///Determine whether tasks are actually executed | |||||
private boolean m_dryRun = false; | |||||
///Enables incremental mode | |||||
private boolean m_incremental; | |||||
///The launcher | |||||
private EmbeddedAnt m_embedded = new EmbeddedAnt(); | |||||
///Log level to use | |||||
private static int m_priority = BasicLogger.LEVEL_WARN; | |||||
/** | |||||
* Main entry point called to run standard Myrmidon. | |||||
* | |||||
* @param args the args | |||||
*/ | |||||
public static void main( final String[] args ) | |||||
{ | |||||
final Map properties = new HashMap(); | |||||
properties.put( "myrmidon.home", new File( "." ) ); | |||||
main( properties, args ); | |||||
} | |||||
/** | |||||
* Main entry point called to run standard Myrmidon. | |||||
* | |||||
* @param args the args | |||||
*/ | |||||
public static void main( final Map properties, final String[] args ) | |||||
{ | |||||
int exitCode = 0; | |||||
final CLIMain main = new CLIMain(); | |||||
try | |||||
{ | |||||
main.execute( properties, args ); | |||||
} | |||||
catch( final Throwable throwable ) | |||||
{ | |||||
main.reportError( throwable ); | |||||
exitCode = -1; | |||||
} | |||||
finally | |||||
{ | |||||
System.exit( exitCode ); | |||||
} | |||||
} | |||||
/** | |||||
* Display usage report. | |||||
* | |||||
*/ | |||||
private void usage( final CLOptionDescriptor[] options ) | |||||
{ | |||||
System.out.println( "ant [options] [targets]" ); | |||||
System.out.println( "\tAvailable options:" ); | |||||
System.out.println( CLUtil.describeOptions( options ) ); | |||||
} | |||||
/** | |||||
* Initialise the options for command line parser. | |||||
*/ | |||||
private CLOptionDescriptor[] createCLOptions() | |||||
{ | |||||
//TODO: localise | |||||
final CLOptionDescriptor[] options = { | |||||
new CLOptionDescriptor( "help", | |||||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
HELP_OPT, | |||||
REZ.getString( "help.opt" ), | |||||
INFO_OPT_INCOMPAT ), | |||||
new CLOptionDescriptor( "file", | |||||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
FILE_OPT, | |||||
REZ.getString( "file.opt" ) ), | |||||
new CLOptionDescriptor( "log-level", | |||||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
LOG_LEVEL_OPT, | |||||
REZ.getString( "log-level.opt" ), | |||||
LOG_OPT_INCOMPAT ), | |||||
new CLOptionDescriptor( "quiet", | |||||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
QUIET_OPT, | |||||
REZ.getString( "quiet.opt" ), | |||||
LOG_OPT_INCOMPAT ), | |||||
new CLOptionDescriptor( "verbose", | |||||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
VERBOSE_OPT, | |||||
REZ.getString( "verbose.opt" ), | |||||
LOG_OPT_INCOMPAT ), | |||||
new CLOptionDescriptor( "debug", | |||||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
DEBUG_OPT, | |||||
REZ.getString( "debug.opt" ), | |||||
LOG_OPT_INCOMPAT ), | |||||
new CLOptionDescriptor( "listener", | |||||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
LISTENER_OPT, | |||||
REZ.getString( "listener.opt" ), | |||||
LISTENER_OPT_INCOMPAT ), | |||||
new CLOptionDescriptor( "noprefix", | |||||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
NO_PREFIX_OPT, | |||||
REZ.getString( "noprefix.opt" ), | |||||
LISTENER_OPT_INCOMPAT ), | |||||
new CLOptionDescriptor( "version", | |||||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
VERSION_OPT, | |||||
REZ.getString( "version.opt" ), | |||||
INFO_OPT_INCOMPAT ), | |||||
new CLOptionDescriptor( "antlib-path", | |||||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
TASKLIB_DIR_OPT, | |||||
REZ.getString( "tasklib.opt" ) ), | |||||
new CLOptionDescriptor( "ext-path", | |||||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
EXTLIB_DIR_OPT, | |||||
REZ.getString( "extlib.opt" ) ), | |||||
new CLOptionDescriptor( "incremental", | |||||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
INCREMENTAL_OPT, | |||||
REZ.getString( "incremental.opt" ) ), | |||||
new CLOptionDescriptor( "ant-home", | |||||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
HOME_DIR_OPT, | |||||
REZ.getString( "home.opt" ) ), | |||||
new CLOptionDescriptor( "define", | |||||
CLOptionDescriptor.ARGUMENTS_REQUIRED_2, | |||||
DEFINE_OPT, | |||||
REZ.getString( "define.opt" ), | |||||
new int[ 0 ] ), | |||||
new CLOptionDescriptor( "builder-parameter", | |||||
CLOptionDescriptor.ARGUMENTS_REQUIRED_2, | |||||
BUILDER_PARAM_OPT, | |||||
REZ.getString( "build.opt" ) ), | |||||
new CLOptionDescriptor( "dry-run", | |||||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||||
DRY_RUN_OPT, | |||||
REZ.getString( "dry-run.opt" ) ), | |||||
new CLOptionDescriptor( "type", | |||||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||||
TYPE_OPT, | |||||
REZ.getString( "type.opt" ) ) | |||||
}; | |||||
return options; | |||||
} | |||||
private boolean parseCommandLineOptions( final String[] args ) | |||||
throws Exception | |||||
{ | |||||
final CLOptionDescriptor[] options = createCLOptions(); | |||||
final CLArgsParser parser = new CLArgsParser( args, options ); | |||||
if( null != parser.getErrorString() ) | |||||
{ | |||||
final String message = REZ.getString( "error-message", parser.getErrorString() ); | |||||
throw new Exception( message ); | |||||
} | |||||
final List clOptions = parser.getArguments(); | |||||
final int size = clOptions.size(); | |||||
for( int i = 0; i < size; i++ ) | |||||
{ | |||||
final CLOption option = (CLOption)clOptions.get( i ); | |||||
switch( option.getId() ) | |||||
{ | |||||
case HELP_OPT: | |||||
usage( options ); | |||||
return false; | |||||
case VERSION_OPT: | |||||
System.out.println( Constants.BUILD_DESCRIPTION ); | |||||
return false; | |||||
case HOME_DIR_OPT: | |||||
m_embedded.setEmbeddorProperty( "myrmidon.home", option.getArgument() ); | |||||
break; | |||||
case TASKLIB_DIR_OPT: | |||||
m_embedded.setEmbeddorProperty( "myrmidon.antlib.path", option.getArgument() ); | |||||
break; | |||||
case EXTLIB_DIR_OPT: | |||||
m_embedded.setEmbeddorProperty( "myrmidon.ext.path", option.getArgument() ); | |||||
break; | |||||
case LOG_LEVEL_OPT: | |||||
m_priority = mapLogLevel( option.getArgument() ); | |||||
break; | |||||
case VERBOSE_OPT: | |||||
m_priority = BasicLogger.LEVEL_INFO; | |||||
break; | |||||
case DEBUG_OPT: | |||||
m_priority = BasicLogger.LEVEL_DEBUG; | |||||
break; | |||||
case QUIET_OPT: | |||||
m_priority = BasicLogger.LEVEL_ERROR; | |||||
break; | |||||
case INCREMENTAL_OPT: | |||||
m_incremental = true; | |||||
break; | |||||
case FILE_OPT: | |||||
m_embedded.setProjectFile( option.getArgument() ); | |||||
break; | |||||
case LISTENER_OPT: | |||||
m_embedded.setProjectListener( option.getArgument() ); | |||||
break; | |||||
case NO_PREFIX_OPT: | |||||
m_embedded.setProjectListener( "noprefix" ); | |||||
break; | |||||
case DEFINE_OPT: | |||||
m_embedded.setWorkspaceProperty( option.getArgument( 0 ), option.getArgument( 1 ) ); | |||||
break; | |||||
case BUILDER_PARAM_OPT: | |||||
m_embedded.setBuilderProperty( option.getArgument( 0 ), option.getArgument( 1 ) ); | |||||
break; | |||||
case DRY_RUN_OPT: | |||||
m_dryRun = true; | |||||
break; | |||||
case TYPE_OPT: | |||||
m_embedded.setProjectType( option.getArgument( 0 ) ); | |||||
break; | |||||
case 0: | |||||
m_targets.add( option.getArgument() ); | |||||
break; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
private void execute( final Map properties, final String[] args ) | |||||
throws Exception | |||||
{ | |||||
try | |||||
{ | |||||
// Set system properties set up by launcher | |||||
m_embedded.setHomeDirectory( (File)properties.get( "myrmidon.home" ) ); | |||||
// Command line | |||||
if( !parseCommandLineOptions( args ) ) | |||||
{ | |||||
return; | |||||
} | |||||
// Setup logging | |||||
final BasicLogger logger = new BasicLogger( "[myrmidon] ", m_priority ); | |||||
m_embedded.enableLogging( logger ); | |||||
if( m_dryRun ) | |||||
{ | |||||
m_embedded.setEmbeddorProperty( Executor.ROLE, | |||||
"org.apache.myrmidon.components.executor.PrintingExecutor" ); | |||||
} | |||||
// Set the common classloader | |||||
final ClassLoader sharedClassLoader = (ClassLoader)properties.get( "myrmidon.shared.classloader" ); | |||||
m_embedded.setSharedClassLoader( sharedClassLoader ); | |||||
//loop over build if we are in incremental mode.. | |||||
if( !m_incremental ) | |||||
{ | |||||
executeBuild(); | |||||
} | |||||
else | |||||
{ | |||||
executeIncrementalBuild(); | |||||
} | |||||
} | |||||
catch( final Exception e ) | |||||
{ | |||||
final String message = REZ.getString( "build-failed.error" ); | |||||
throw new CascadingException( message, e ); | |||||
} | |||||
finally | |||||
{ | |||||
m_embedded.stop(); | |||||
} | |||||
} | |||||
private void executeIncrementalBuild() | |||||
throws Exception | |||||
{ | |||||
BufferedReader reader = null; | |||||
while( true ) | |||||
{ | |||||
try | |||||
{ | |||||
executeBuild(); | |||||
} | |||||
catch( final TaskException te ) | |||||
{ | |||||
reportError( te ); | |||||
} | |||||
final String message = REZ.getString( "repeat.notice" ); | |||||
System.out.println( message ); | |||||
if( null == reader ) | |||||
{ | |||||
reader = new BufferedReader( new InputStreamReader( System.in ) ); | |||||
} | |||||
String line = reader.readLine(); | |||||
if( line.equalsIgnoreCase( "no" ) ) | |||||
{ | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
private void executeBuild() throws Exception | |||||
{ | |||||
//actually do the build ... | |||||
final String[] targets = (String[])m_targets.toArray( new String[ m_targets.size() ] ); | |||||
m_embedded.executeTargets( targets ); | |||||
} | |||||
/** | |||||
* Builds the error message for an exception | |||||
*/ | |||||
private void reportError( final Throwable throwable ) | |||||
{ | |||||
// Build the message | |||||
final String message; | |||||
if( m_priority <= BasicLogger.LEVEL_INFO ) | |||||
{ | |||||
// Verbose mode - include the stack traces | |||||
message = ExceptionUtil.printStackTrace( throwable, 8, true, true ); | |||||
} | |||||
else | |||||
{ | |||||
// Build the message | |||||
final StringBuffer buffer = new StringBuffer(); | |||||
buffer.append( throwable.getMessage() ); | |||||
for( Throwable current = ExceptionUtil.getCause( throwable, true ); | |||||
current != null; | |||||
current = ExceptionUtil.getCause( current, true ) ) | |||||
{ | |||||
final String causeMessage = REZ.getString( "cause.error", current.getMessage() ); | |||||
buffer.append( causeMessage ); | |||||
} | |||||
message = buffer.toString(); | |||||
} | |||||
// Write the message out | |||||
System.err.println( message ); | |||||
} | |||||
/** | |||||
* Sets the log level. | |||||
*/ | |||||
private int mapLogLevel( final String logLevel ) | |||||
throws Exception | |||||
{ | |||||
final String logLevelCapitalized = logLevel.toUpperCase(); | |||||
if( "DEBUG".equals( logLevelCapitalized ) ) | |||||
{ | |||||
return BasicLogger.LEVEL_DEBUG; | |||||
} | |||||
else if( "VERBOSE".equals( logLevelCapitalized ) ) | |||||
{ | |||||
return BasicLogger.LEVEL_INFO; | |||||
} | |||||
else if( "INFO".equals( logLevelCapitalized ) ) | |||||
{ | |||||
return BasicLogger.LEVEL_WARN; | |||||
} | |||||
else if( "WARN".equals( logLevelCapitalized ) ) | |||||
{ | |||||
return BasicLogger.LEVEL_ERROR; | |||||
} | |||||
else if( "ERROR".equals( logLevelCapitalized ) ) | |||||
{ | |||||
return BasicLogger.LEVEL_FATAL; | |||||
} | |||||
else | |||||
{ | |||||
final String message = REZ.getString( "bad-loglevel.error", logLevel ); | |||||
throw new Exception( message ); | |||||
} | |||||
} | |||||
} |
@@ -1,420 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.frontends; | |||||
import java.io.File; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
import org.apache.avalon.excalibur.io.FileUtil; | |||||
import org.apache.avalon.excalibur.util.StringUtil; | |||||
import org.apache.avalon.framework.activity.Disposable; | |||||
import org.apache.avalon.framework.activity.Initializable; | |||||
import org.apache.avalon.framework.activity.Startable; | |||||
import org.apache.avalon.framework.context.Context; | |||||
import org.apache.avalon.framework.context.Contextualizable; | |||||
import org.apache.avalon.framework.context.DefaultContext; | |||||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
import org.apache.avalon.framework.parameters.Parameters; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.interfaces.embeddor.Embeddor; | |||||
import org.apache.myrmidon.interfaces.model.Project; | |||||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||||
import org.apache.myrmidon.listeners.ProjectListener; | |||||
/** | |||||
* A utility class, that takes care of launching Myrmidon, and building and | |||||
* executing a project. | |||||
* | |||||
* <p>To use this class, create an instance and configure. To execute | |||||
* targets in a project, use the {@link #executeTargets} method. This can | |||||
* be done one or more times. Finally, call the {@link #stop} method to | |||||
* clean-up. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class EmbeddedAnt | |||||
extends AbstractLogEnabled | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( EmbeddedAnt.class ); | |||||
private static final String DEFAULT_EMBEDDOR_CLASS = | |||||
"org.apache.myrmidon.components.embeddor.DefaultEmbeddor"; | |||||
private final ArrayList m_listeners = new ArrayList(); | |||||
private final Parameters m_builderProps = new Parameters(); | |||||
private final Map m_embeddorParameters = new HashMap(); | |||||
private final Map m_workspaceProperties = new HashMap(); | |||||
private String m_projectFile = "build.ant"; | |||||
private Project m_project; | |||||
private String m_listenerName = "default"; | |||||
private ClassLoader m_sharedClassLoader; | |||||
private Embeddor m_embeddor; | |||||
private File m_homeDir; | |||||
private String m_projectType; | |||||
/** | |||||
* Sets the Myrmidon home directory. Default is to use the current | |||||
* directory. | |||||
* | |||||
* @todo Autodetect myrmidon home, rather than using current directory | |||||
* as the default (which is a dud default). | |||||
*/ | |||||
public void setHomeDirectory( final File homeDir ) | |||||
{ | |||||
m_homeDir = homeDir.getAbsoluteFile(); | |||||
} | |||||
/** | |||||
* Sets the project file to execute. Default is 'build.ant'. | |||||
*/ | |||||
public void setProjectFile( final String projectFile ) | |||||
{ | |||||
m_projectFile = projectFile; | |||||
m_project = null; | |||||
} | |||||
/** | |||||
* Sets the project file type. Ignored if {@link #setProject} is used. | |||||
* Set to null to use the default project type. | |||||
*/ | |||||
public void setProjectType( final String projectType ) | |||||
{ | |||||
m_projectType = projectType; | |||||
} | |||||
/** | |||||
* Sets the project to execute. This method can be used instead of | |||||
* {@link #setProjectFile}, for projects models that are built | |||||
* programmatically. | |||||
*/ | |||||
public void setProject( final Project project ) | |||||
{ | |||||
m_projectFile = null; | |||||
m_project = project; | |||||
} | |||||
/** | |||||
* Sets the name of the project listener to use. Set to null to disable | |||||
* the project listener. | |||||
*/ | |||||
public void setProjectListener( final String listener ) | |||||
{ | |||||
m_listenerName = listener; | |||||
} | |||||
/** | |||||
* Adds a project listener. | |||||
*/ | |||||
public void addProjectListener( final ProjectListener listener ) | |||||
{ | |||||
m_listeners.add( listener ); | |||||
} | |||||
/** | |||||
* Sets a workspace property. These are inherited by all projects executed | |||||
* by this embeddor. | |||||
*/ | |||||
public void setWorkspaceProperty( final String name, final Object value ) | |||||
{ | |||||
m_workspaceProperties.put( name, value ); | |||||
} | |||||
/** | |||||
* Sets a project builder property. These are used by the project builder | |||||
* when it is parsing the project file. | |||||
*/ | |||||
public void setBuilderProperty( final String name, final Object value ) | |||||
{ | |||||
// TODO - Make properties Objects, not Strings | |||||
m_builderProps.setParameter( name, value.toString() ); | |||||
} | |||||
/** | |||||
* Sets a task engine property. These are used to configure the task engine. | |||||
* | |||||
* @todo Make this method actually work with objects... | |||||
*/ | |||||
public void setEmbeddorProperty( final String name, final Object value ) | |||||
{ | |||||
m_embeddorParameters.put( name, value.toString() ); | |||||
} | |||||
/** | |||||
* Sets the shared classloader, which is used as the parent classloader | |||||
* for all antlibs. Default is to use the context classloader. | |||||
*/ | |||||
public void setSharedClassLoader( final ClassLoader classLoader ) | |||||
{ | |||||
m_sharedClassLoader = classLoader; | |||||
} | |||||
/** | |||||
* Executes a set of targets in the project. This method may be called | |||||
* multiple times. | |||||
*/ | |||||
public void executeTargets( final String[] targets ) throws Exception | |||||
{ | |||||
Map embeddorParameters = new HashMap( m_embeddorParameters ); | |||||
setupPaths( embeddorParameters ); | |||||
if( m_sharedClassLoader != null ) | |||||
{ | |||||
embeddorParameters.put( "myrmidon.shared.classloader", m_sharedClassLoader ); | |||||
} | |||||
// Prepare the embeddor, and project model | |||||
final Embeddor embeddor = prepareEmbeddor( embeddorParameters ); | |||||
final Project project = prepareProjectModel( embeddor ); | |||||
// Create a new workspace | |||||
final Workspace workspace = embeddor.createWorkspace( m_workspaceProperties ); | |||||
prepareListeners( embeddor, workspace ); | |||||
//execute the project | |||||
executeTargets( workspace, project, targets ); | |||||
} | |||||
/** | |||||
* Shuts down the task engine, after the project has been executed. | |||||
*/ | |||||
public void stop() throws Exception | |||||
{ | |||||
try | |||||
{ | |||||
if( m_embeddor != null ) | |||||
{ | |||||
if( m_embeddor instanceof Startable ) | |||||
{ | |||||
( (Startable)m_embeddor ).stop(); | |||||
} | |||||
if( m_embeddor instanceof Disposable ) | |||||
{ | |||||
( (Disposable)m_embeddor ).dispose(); | |||||
} | |||||
} | |||||
} | |||||
finally | |||||
{ | |||||
m_embeddor = null; | |||||
m_project = null; | |||||
m_listeners.clear(); | |||||
} | |||||
} | |||||
/** | |||||
* Actually do the build. | |||||
*/ | |||||
private void executeTargets( final Workspace workspace, | |||||
final Project project, | |||||
final String[] targets ) | |||||
throws TaskException | |||||
{ | |||||
//if we didn't specify a target, then choose default | |||||
if( targets == null || targets.length == 0 ) | |||||
{ | |||||
workspace.executeProject( project, project.getDefaultTargetName() ); | |||||
} | |||||
else | |||||
{ | |||||
for( int i = 0; i < targets.length; i++ ) | |||||
{ | |||||
workspace.executeProject( project, targets[ i ] ); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Make sure myrmidon home directory has been specified, and is a | |||||
* directory. Set the paths that the embeddor expects. | |||||
*/ | |||||
private void setupPaths( Map parameters ) throws Exception | |||||
{ | |||||
if( m_homeDir == null ) | |||||
{ | |||||
m_homeDir = new File( "." ).getAbsoluteFile(); | |||||
} | |||||
checkDirectory( m_homeDir, "home-dir.name" ); | |||||
parameters.put( "myrmidon.home", m_homeDir ); | |||||
if( getLogger().isInfoEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( "homedir.notice", m_homeDir ); | |||||
getLogger().info( message ); | |||||
} | |||||
// Build the lib path | |||||
String path = (String)parameters.get( "myrmidon.lib.path" ); | |||||
File[] dirs = buildPath( m_homeDir, path, "lib", "lib-dir.name" ); | |||||
parameters.put( "myrmidon.lib.path", dirs ); | |||||
// Build the antlib search path | |||||
path = (String)parameters.get( "myrmidon.antlib.path" ); | |||||
dirs = buildPath( m_homeDir, path, "ext", "task-lib-dir.name" ); | |||||
parameters.put( "myrmidon.antlib.path", dirs ); | |||||
// Build the extension search path | |||||
path = (String)parameters.get( "myrmidon.ext.path" ); | |||||
dirs = buildPath( m_homeDir, path, "ext", "ext-dir.name" ); | |||||
parameters.put( "myrmidon.ext.path", dirs ); | |||||
} | |||||
/** | |||||
* Prepares and returns the embeddor to use. | |||||
*/ | |||||
private Embeddor prepareEmbeddor( final Map parameters ) | |||||
throws Exception | |||||
{ | |||||
if( m_embeddor == null ) | |||||
{ | |||||
m_embeddor = createEmbeddor(); | |||||
setupLogger( m_embeddor ); | |||||
if( m_embeddor instanceof Contextualizable ) | |||||
{ | |||||
final Context context = new DefaultContext( parameters ); | |||||
( (Contextualizable)m_embeddor ).contextualize( context ); | |||||
} | |||||
if( m_embeddor instanceof Initializable ) | |||||
{ | |||||
( (Initializable)m_embeddor ).initialize(); | |||||
} | |||||
if( m_embeddor instanceof Startable ) | |||||
{ | |||||
( (Startable)m_embeddor ).start(); | |||||
} | |||||
} | |||||
return m_embeddor; | |||||
} | |||||
/** | |||||
* Creates the embeddor. | |||||
*/ | |||||
private Embeddor createEmbeddor() | |||||
throws Exception | |||||
{ | |||||
final Class clazz = Class.forName( DEFAULT_EMBEDDOR_CLASS ); | |||||
return (Embeddor)clazz.newInstance(); | |||||
} | |||||
/** | |||||
* Prepares and returns the project listener to use. | |||||
*/ | |||||
private void prepareListeners( final Embeddor embeddor, | |||||
final Workspace workspace ) | |||||
throws Exception | |||||
{ | |||||
if( m_listenerName != null ) | |||||
{ | |||||
final ProjectListener listener = embeddor.createListener( m_listenerName ); | |||||
workspace.addProjectListener( listener ); | |||||
} | |||||
final int count = m_listeners.size(); | |||||
for( int i = 0; i < count; i++ ) | |||||
{ | |||||
final ProjectListener listener = (ProjectListener)m_listeners.get( i ); | |||||
workspace.addProjectListener( listener ); | |||||
} | |||||
} | |||||
/** | |||||
* Prepares and returns the project model. | |||||
*/ | |||||
private Project prepareProjectModel( final Embeddor embeddor ) throws Exception | |||||
{ | |||||
if( m_project == null ) | |||||
{ | |||||
final File buildFile = getProjectFile(); | |||||
m_project = embeddor.createProject( buildFile.toString(), m_projectType, m_builderProps ); | |||||
} | |||||
return m_project; | |||||
} | |||||
/** | |||||
* Locates the project file | |||||
*/ | |||||
private File getProjectFile() throws Exception | |||||
{ | |||||
final File projectFile = ( new File( m_projectFile ) ).getCanonicalFile(); | |||||
if( !projectFile.isFile() ) | |||||
{ | |||||
final String message = REZ.getString( "bad-file.error", projectFile ); | |||||
throw new Exception( message ); | |||||
} | |||||
if( getLogger().isInfoEnabled() ) | |||||
{ | |||||
final String message = REZ.getString( "buildfile.notice", projectFile ); | |||||
getLogger().info( message ); | |||||
} | |||||
return projectFile; | |||||
} | |||||
/** | |||||
* Resolve a directory relative to another base directory. | |||||
*/ | |||||
private File[] buildPath( final File baseDir, | |||||
final String path, | |||||
final String defaultPath, | |||||
final String name ) | |||||
throws Exception | |||||
{ | |||||
// Build the canonical list of files | |||||
final ArrayList files = new ArrayList(); | |||||
// Add the default path | |||||
files.add( FileUtil.resolveFile( baseDir, defaultPath ) ); | |||||
// Add the additional path | |||||
if( path != null ) | |||||
{ | |||||
final String[] split = StringUtil.split( path, File.pathSeparator ); | |||||
for( int i = 0; i < split.length; i++ ) | |||||
{ | |||||
final String s = split[ i ]; | |||||
final File file = new File( s ).getAbsoluteFile(); | |||||
files.add( file ); | |||||
} | |||||
} | |||||
// Check each one | |||||
for( int i = 0; i < files.size(); i++ ) | |||||
{ | |||||
File file = (File)files.get( i ); | |||||
checkDirectory( file, name ); | |||||
} | |||||
return (File[])files.toArray( new File[ files.size() ] ); | |||||
} | |||||
/** | |||||
* Verify file is a directory else throw an exception. | |||||
*/ | |||||
private void checkDirectory( final File file, final String name ) | |||||
throws Exception | |||||
{ | |||||
if( !file.exists() ) | |||||
{ | |||||
final String nameStr = REZ.getString( name ); | |||||
final String message = REZ.getString( "file-no-exist.error", nameStr, file ); | |||||
throw new Exception( message ); | |||||
} | |||||
else if( !file.isDirectory() ) | |||||
{ | |||||
final String nameStr = REZ.getString( name ); | |||||
final String message = REZ.getString( "file-not-dir.error", nameStr, file ); | |||||
throw new Exception( message ); | |||||
} | |||||
} | |||||
} |
@@ -1,35 +0,0 @@ | |||||
error-message=Error: {0}. | |||||
help.opt=Display this help message. | |||||
file.opt=Specify the build file. | |||||
log-level.opt=Specify the verbosity level at which to log messages. (DEBUG|VERBOSE|INFO|WARN|ERROR). | |||||
quiet.opt=Equivalent to --log-level=ERROR. | |||||
verbose.opt=Equivalent to --log-level=VERBOSE. | |||||
debug.opt=Equivalent to --log-level=DEBUG. | |||||
listener.opt=Specify the listener for log events. | |||||
noprefix.opt=Do not prefix output with the task name. Equivalent to --listener noprefix. | |||||
version.opt=Display version. | |||||
tasklib.opt=Specify the path to use to search for antlib libraries. | |||||
extlib.opt=Specify the path to use to search for optional packages. | |||||
incremental.opt=Run in incremental mode. | |||||
home.opt=Specify Ant home directory. | |||||
define.opt=Define a property (ie -Dfoo=var). | |||||
build.opt=Define a builder parameter (ie -Bfoo=var). | |||||
dry-run.opt=Do not execute tasks - just print them out. | |||||
type.opt=Specify the project file type. | |||||
file-no-exist.error={0} {1} does not exist. | |||||
file-not-dir.error={0} {1} is not a directory. | |||||
bad-file.error=File {0} is not a file or doesn't exist. | |||||
bad-loglevel.error=Unknown log level - {0}. | |||||
build-failed.error=BUILD FAILED. | |||||
cause.error=\nReason: {0} | |||||
repeat.notice=Continue ? (Enter no to stop) | |||||
homedir.notice=Ant Home Directory: {0} | |||||
buildfile.notice=Ant Build File: {0} | |||||
home-dir.name=Ant home directory | |||||
lib-dir.name=Library directory | |||||
task-lib-dir.name=Antlib directory | |||||
ext-dir.name=Extension directory |
@@ -1,56 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces; | |||||
/** | |||||
* An exception thrown by a Myrmidon component. This is a convenience | |||||
* class, which can be sub-classes to create exceptions for specific components. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class ComponentException | |||||
extends Exception | |||||
{ | |||||
/** | |||||
* The Throwable that caused this exception to be thrown. | |||||
*/ | |||||
private final Throwable m_throwable; | |||||
/** | |||||
* Constructs a non-cascaded exception. | |||||
* | |||||
* @param message The detail message for this exception. | |||||
*/ | |||||
public ComponentException( final String message ) | |||||
{ | |||||
this( message, null ); | |||||
} | |||||
/** | |||||
* Constructs a cascaded exception. | |||||
* | |||||
* @param message The detail message for this exception. | |||||
* @param throwable the root cause of the exception | |||||
*/ | |||||
public ComponentException( final String message, final Throwable throwable ) | |||||
{ | |||||
super( message ); | |||||
m_throwable = throwable; | |||||
} | |||||
/** | |||||
* Retrieve root cause of the exception. | |||||
* | |||||
* @return the root cause | |||||
*/ | |||||
public final Throwable getCause() | |||||
{ | |||||
return m_throwable; | |||||
} | |||||
} |
@@ -1,59 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.aspect; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.parameters.Parameters; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.aspects.AspectHandler; | |||||
/** | |||||
* Manage and propogate Aspects.. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface AspectManager | |||||
extends AspectHandler | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = AspectManager.class.getName(); | |||||
/** | |||||
* @return The names of all AspectHandlers managed. | |||||
*/ | |||||
String[] getNames(); | |||||
/** | |||||
* Dispatches aspect settings to the named AspectHandler. | |||||
* @param name The name of the AspectHandler to recieve the settings. | |||||
* @param parameters The parameter settings. | |||||
* @param elements The nested Configuration settings. | |||||
* @throws TaskException if the named AspectHandler doesn't exist, | |||||
* or it cannot handle the settings. | |||||
*/ | |||||
void dispatchAspectSettings( String name, Parameters parameters, Configuration[] elements ) | |||||
throws TaskException; | |||||
/** | |||||
* Adds a named aspect handler to the manager. | |||||
* @param name The name used to lookup the aspect handler. | |||||
* @param handler The aspect handler to add. | |||||
* @throws TaskException If an error occurs. | |||||
*/ | |||||
void addAspectHandler( String name, AspectHandler handler ) | |||||
throws TaskException; | |||||
/** | |||||
* Removes a named aspect handler from the manager. | |||||
* @param name The name of the handler to remove. | |||||
* @throws TaskException If the named handler doesn't exist. | |||||
*/ | |||||
void removeAspectHandler( String name ) | |||||
throws TaskException; | |||||
} |
@@ -1,33 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.builder; | |||||
import org.apache.myrmidon.interfaces.model.Project; | |||||
/** | |||||
* Interface implemented by components that build projects from sources. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
* @ant:role shorthand="project-builder" | |||||
*/ | |||||
public interface ProjectBuilder | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = ProjectBuilder.class.getName(); | |||||
/** | |||||
* build a project from source. | |||||
* | |||||
* @param source the project file path. | |||||
* @return the constructed Project | |||||
* @exception ProjectException if an error occurs | |||||
*/ | |||||
Project build( String source ) | |||||
throws ProjectException; | |||||
} |
@@ -1,41 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.builder; | |||||
import org.apache.myrmidon.interfaces.ComponentException; | |||||
/** | |||||
* A cascading exception thrown on a problem constructing a Project model. | |||||
* | |||||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class ProjectException | |||||
extends ComponentException | |||||
{ | |||||
/** | |||||
* Constructs a non-cascaded exception. | |||||
* | |||||
* @param message The detail message for this exception. | |||||
*/ | |||||
public ProjectException( final String message ) | |||||
{ | |||||
super( message ); | |||||
} | |||||
/** | |||||
* Constructs a cascaded exception. | |||||
* | |||||
* @param message The detail message for this exception. | |||||
* @param throwable the root cause of the exception | |||||
*/ | |||||
public ProjectException( final String message, final Throwable throwable ) | |||||
{ | |||||
super( message, throwable ); | |||||
} | |||||
} |
@@ -1,41 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.classloader; | |||||
import org.apache.myrmidon.interfaces.ComponentException; | |||||
/** | |||||
* An exception thrown by the ClassLoaderManager. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class ClassLoaderException | |||||
extends ComponentException | |||||
{ | |||||
/** | |||||
* Constructs a non-cascaded exception. | |||||
* | |||||
* @param message The detail message for this exception. | |||||
*/ | |||||
public ClassLoaderException( final String message ) | |||||
{ | |||||
super( message ); | |||||
} | |||||
/** | |||||
* Constructs a cascaded exception. | |||||
* | |||||
* @param message The detail message for this exception. | |||||
* @param throwable the root cause of the exception | |||||
*/ | |||||
public ClassLoaderException( final String message, final Throwable throwable ) | |||||
{ | |||||
super( message, throwable ); | |||||
} | |||||
} |
@@ -1,55 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.classloader; | |||||
import java.io.File; | |||||
/** | |||||
* Manages a classloader hierarchy. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface ClassLoaderManager | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = ClassLoaderManager.class.getName(); | |||||
/** | |||||
* Returns the ClassLoader for a Jar file. The ClassLoader is created, | |||||
* if necessary. The ClassLoader's parent will include the common | |||||
* ClassLoader, along with any extensions required by the Jar file. | |||||
* It is guaranteed that each extension will appear at most once in the | |||||
* ClassLoader hierarchy, so that classes from the extension can be | |||||
* shared across the ClassLoaders returned by this method. | |||||
* | |||||
* @param jar the jar file containing the classes to load | |||||
* @return the classloader | |||||
* @throws ClassLoaderException on error | |||||
*/ | |||||
ClassLoader getClassLoader( File jar ) throws ClassLoaderException; | |||||
/** | |||||
* Creates a ClassLoader for a set of files. See {@link #getClassLoader} | |||||
* for details. | |||||
* | |||||
* @param jars The Jar/zip files to create the classloader for. Use null | |||||
* or an empty array to use the common classloader. | |||||
* @return the created ClassLoader | |||||
* @throws ClassLoaderException on error | |||||
*/ | |||||
ClassLoader createClassLoader( File[] jars ) throws ClassLoaderException; | |||||
/** | |||||
* Returns the common ClassLoader, which is the parent of all classloaders | |||||
* built by this ClassLoaderManager. | |||||
* | |||||
* @return the common ClassLoader. | |||||
*/ | |||||
ClassLoader getCommonClassLoader(); | |||||
} |
@@ -1,98 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.configurer; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
/** | |||||
* Class used to configure tasks. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
* @ant:role shorthand="configurer" | |||||
*/ | |||||
public interface Configurer | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = Configurer.class.getName(); | |||||
/** | |||||
* Configure an object based on a configuration in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* @param object the object | |||||
* @param configuration the configuration | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
void configureElement( Object object, Configuration configuration, TaskContext context ) | |||||
throws ConfigurationException; | |||||
/** | |||||
* Configure named attribute of object in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* @param object the object | |||||
* @param name the attribute name | |||||
* @param value the attribute value | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
void configureAttribute( Object object, String name, String value, TaskContext context ) | |||||
throws ConfigurationException; | |||||
/** | |||||
* Configure an object based on a configuration in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* The implementation of this method should only use the methods | |||||
* specified by the supplied class. It is an error for the specified | |||||
* class not to be a base class or interface compatible with specified | |||||
* object. | |||||
* | |||||
* @param object the object | |||||
* @param clazz the Class object to use during configuration | |||||
* @param configuration the configuration | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
void configureElement( Object object, | |||||
Class clazz, | |||||
Configuration configuration, | |||||
TaskContext context ) | |||||
throws ConfigurationException; | |||||
/** | |||||
* Configure named attribute of object in a particular context. | |||||
* This configuring can be done in different ways for different | |||||
* configurers. | |||||
* | |||||
* The implementation of this method should only use the methods | |||||
* specified by the supplied class. It is an error for the specified | |||||
* class not to be a base class or interface compatible with specified | |||||
* object. | |||||
* | |||||
* @param object the object | |||||
* @param clazz the Class object to use during configuration | |||||
* @param name the attribute name | |||||
* @param value the attribute value | |||||
* @param context the Context | |||||
* @exception ConfigurationException if an error occurs | |||||
*/ | |||||
void configureAttribute( Object object, | |||||
Class clazz, | |||||
String name, | |||||
String value, | |||||
TaskContext context ) | |||||
throws ConfigurationException; | |||||
} |
@@ -1,29 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.converter; | |||||
/** | |||||
* Interface for registry for ConverterInfos. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface ConverterRegistry | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = ConverterRegistry.class.getName(); | |||||
/** | |||||
* Register a converter | |||||
* | |||||
* @param className the className of converter | |||||
* @param source the source classname | |||||
* @param destination the destination classname | |||||
*/ | |||||
void registerConverter( String className, String source, String destination ); | |||||
} |
@@ -1,54 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.deployer; | |||||
/** | |||||
* A specialised TypeDefinition which defines a converter. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class ConverterDefinition | |||||
extends TypeDefinition | |||||
{ | |||||
private final String m_sourceType; | |||||
private final String m_destinationType; | |||||
/** | |||||
* Creates a converter definition. | |||||
* @param className the name of the implementing class | |||||
* @param sourceType the name of the types converted from | |||||
* @param destinationType the name of the type converted to | |||||
*/ | |||||
public ConverterDefinition( final String className, | |||||
final String sourceType, | |||||
final String destinationType ) | |||||
{ | |||||
super( className, "converter", className ); | |||||
m_sourceType = sourceType; | |||||
m_destinationType = destinationType; | |||||
} | |||||
/** | |||||
* Provides the name of the type which this converter can convert from. | |||||
* @return the converter's source type. | |||||
*/ | |||||
public String getSourceType() | |||||
{ | |||||
return m_sourceType; | |||||
} | |||||
/** | |||||
* Provides the name of the type which this converter can convert to. | |||||
* @return the converter's destination type. | |||||
*/ | |||||
public String getDestinationType() | |||||
{ | |||||
return m_destinationType; | |||||
} | |||||
} |
@@ -1,55 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.deployer; | |||||
import java.io.File; | |||||
import org.apache.avalon.framework.service.ServiceException; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
/** | |||||
* This class deploys type libraries into a registry. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface Deployer | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = Deployer.class.getName(); | |||||
/** | |||||
* Returns the deployer for the type libraries contained in a ClassLoader, | |||||
* creating the deployer if necessary. | |||||
* | |||||
* @param loader The ClassLoader to get the deployer for. | |||||
* @return the deployer for this loader. | |||||
* @exception DeploymentException if an error occurs. | |||||
*/ | |||||
TypeDeployer createDeployer( ClassLoader loader ) | |||||
throws DeploymentException; | |||||
/** | |||||
* Returns the deployer for a type library, creating the deployer if | |||||
* necessary. | |||||
* | |||||
* @param file the file containing the type library. | |||||
* @return the deployer for this type library. | |||||
* @exception DeploymentException if an error occurs. | |||||
*/ | |||||
TypeDeployer createDeployer( File file ) | |||||
throws DeploymentException; | |||||
/** | |||||
* Creates a deployer which is a child of this deployer. | |||||
* @param componentManager the ServiceManager for this component. | |||||
* @return a child deployer. | |||||
* @throws ServiceException if an error occurs. | |||||
*/ | |||||
Deployer createChildDeployer( ServiceManager componentManager ) | |||||
throws ServiceException; | |||||
} |
@@ -1,41 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.deployer; | |||||
import org.apache.myrmidon.interfaces.ComponentException; | |||||
/** | |||||
* Exception to indicate error deploying. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DeploymentException | |||||
extends ComponentException | |||||
{ | |||||
/** | |||||
* Constructs a non-cascaded exception. | |||||
* | |||||
* @param message The detail message for this exception. | |||||
*/ | |||||
public DeploymentException( final String message ) | |||||
{ | |||||
super( message ); | |||||
} | |||||
/** | |||||
* Constructs a cascaded exception. | |||||
* | |||||
* @param message The detail message for this exception. | |||||
* @param throwable the root cause of the exception | |||||
*/ | |||||
public DeploymentException( final String message, final Throwable throwable ) | |||||
{ | |||||
super( message, throwable ); | |||||
} | |||||
} |
@@ -1,60 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.deployer; | |||||
/** | |||||
* A general-purpose type definition. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class TypeDefinition | |||||
{ | |||||
private final String m_name; | |||||
private final String m_role; | |||||
private final String m_classname; | |||||
/** | |||||
* Creates a TypeDefinition | |||||
* @param name the name of the type | |||||
* @param roleShorthand the name of the role played by this type | |||||
* @param className the name of the class implementing this type | |||||
*/ | |||||
public TypeDefinition( final String name, | |||||
final String roleShorthand, | |||||
final String className ) | |||||
{ | |||||
m_name = name; | |||||
m_role = roleShorthand; | |||||
m_classname = className; | |||||
} | |||||
/** | |||||
* @return the type's implementation class name. | |||||
*/ | |||||
public final String getClassname() | |||||
{ | |||||
return m_classname; | |||||
} | |||||
/** | |||||
* @return the type's role. | |||||
*/ | |||||
public final String getRole() | |||||
{ | |||||
return m_role; | |||||
} | |||||
/** | |||||
* @return the type's name. | |||||
*/ | |||||
public String getName() | |||||
{ | |||||
return m_name; | |||||
} | |||||
} |
@@ -1,54 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.deployer; | |||||
/** | |||||
* A deployer for a type library. Allows individual elements from a type | |||||
* library to be deployed. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface TypeDeployer | |||||
{ | |||||
/** | |||||
* Deploys everything in the type library. | |||||
* @throws DeploymentException | |||||
* If the library cannot be deployed. | |||||
*/ | |||||
void deployAll() | |||||
throws DeploymentException; | |||||
/** | |||||
* Deploys a single type from the type library. The type definition is | |||||
* read from the type library descriptor. | |||||
* | |||||
* @param roleShorthand | |||||
* The shorthand name for the role. | |||||
* | |||||
* @param typeName | |||||
* The type name. | |||||
* | |||||
* @throws DeploymentException | |||||
* If the type cannot be deployed. | |||||
*/ | |||||
void deployType( String roleShorthand, String typeName ) | |||||
throws DeploymentException; | |||||
/** | |||||
* Deploys a single type from the type library. | |||||
* | |||||
* @param typeDef | |||||
* The type definition. | |||||
* | |||||
* @throws DeploymentException | |||||
* If the type cannot be deployed. | |||||
*/ | |||||
void deployType( TypeDefinition typeDef ) | |||||
throws DeploymentException; | |||||
} |
@@ -1,65 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.embeddor; | |||||
import org.apache.avalon.framework.parameters.Parameters; | |||||
import org.apache.myrmidon.interfaces.model.Project; | |||||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||||
import org.apache.myrmidon.listeners.ProjectListener; | |||||
import java.util.Map; | |||||
/** | |||||
* Interface through which you embed Myrmidon into applications. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface Embeddor | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = Embeddor.class.getName(); | |||||
/** | |||||
* Creates a project from a project file. | |||||
* | |||||
* @param location The path to the project file. | |||||
* @param type The project file type. If null the type is inferred from the | |||||
* project file name. | |||||
* @param parameters The project builder parameters. | |||||
* @return the created Project | |||||
* @throws Exception If an error occurs creating the Project. | |||||
* | |||||
* @todo Should location be a URL or will it automatically assume file | |||||
* unless there is a protocol section like ftp:, file: etc | |||||
* @todo parameters needs more thought put into it. | |||||
*/ | |||||
Project createProject( String location, String type, Parameters parameters ) | |||||
throws Exception; | |||||
/** | |||||
* Creates a project listener. | |||||
* | |||||
* @param name The shorthand name of the listener. | |||||
* @return the listener. | |||||
* @throws Exception If the listener could not be created. | |||||
*/ | |||||
ProjectListener createListener( String name ) | |||||
throws Exception; | |||||
/** | |||||
* Creates a {@link Workspace} that can be used to execute projects. | |||||
* | |||||
* @param properties The properties to define in the workspace. These | |||||
* are added to the properties in the embeddor's | |||||
* root execution frame. | |||||
* @return the Workspace | |||||
* @throws Exception If the workspace could not be created. | |||||
*/ | |||||
Workspace createWorkspace( Map properties ) | |||||
throws Exception; | |||||
} |
@@ -1,23 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.executor; | |||||
/** | |||||
* This interface is used to supply a root execution frame to a container | |||||
* that executes tasks. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface ExecutionContainer | |||||
{ | |||||
/** | |||||
* Sets the root execution frame for the container. | |||||
*/ | |||||
void setRootExecutionFrame( ExecutionFrame frame ) throws Exception; | |||||
} |
@@ -1,46 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.executor; | |||||
import org.apache.avalon.framework.logger.Logger; | |||||
import org.apache.avalon.framework.service.ServiceManager; | |||||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||||
/** | |||||
* An Execution Frame represents the scope in which tasks are executed. | |||||
* The scope may include an entire workspace, a project, target, or | |||||
* individual task. | |||||
* | |||||
* <p>An Execution Frame bundles together all of the context required to | |||||
* execute tasks - that is, a set of properties, a set of services, and | |||||
* a logger. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface ExecutionFrame | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = ExecutionFrame.class.getName(); | |||||
/** | |||||
* Returns the set of services to use to create, configure, and execute | |||||
* tasks. | |||||
*/ | |||||
ServiceManager getServiceManager(); | |||||
/** | |||||
* Returns the logger which is to be supplied to tasks. | |||||
*/ | |||||
Logger getLogger(); | |||||
/** | |||||
* Returns the set of properties to be supplied to tasks. | |||||
*/ | |||||
PropertyStore getProperties(); | |||||
} |
@@ -1,33 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.executor; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
/** | |||||
* Engine inteface that should be implemented by all tasklet engines. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface Executor | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = Executor.class.getName(); | |||||
/** | |||||
* execute a task. | |||||
* | |||||
* @param task the configruation data for task | |||||
* @param frame The frame in which the task is executed. | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
void execute( Configuration task, ExecutionFrame frame ) | |||||
throws TaskException; | |||||
} |
@@ -1,31 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.extensions; | |||||
import org.apache.avalon.excalibur.extension.Extension; | |||||
import org.apache.avalon.excalibur.extension.OptionalPackage; | |||||
/** | |||||
* Maintains a set of optional packages. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface ExtensionManager | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = ExtensionManager.class.getName(); | |||||
/** | |||||
* Locates the optional package which best matches a required extension. | |||||
* | |||||
* @param extension the extension to locate an optional package | |||||
* @return the optional package, or null if not found. | |||||
*/ | |||||
OptionalPackage getOptionalPackage( Extension extension ); | |||||
} |
@@ -1,356 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.model; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
/** | |||||
* Simple helper class which determines the validity of names used | |||||
* in ant projects. | |||||
* | |||||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class DefaultNameValidator | |||||
implements NameValidator | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( DefaultNameValidator.class ); | |||||
/** | |||||
* Determines whether the supplied name may include surrounding whitespace. | |||||
*/ | |||||
private boolean m_allowSurroundingWhitespace; | |||||
// Settings for initial characters. | |||||
private boolean m_allowInitialDigit; | |||||
private String m_additionalInitialCharacters; | |||||
// Settings for internal characters. | |||||
private boolean m_allowInternalDigits; | |||||
private boolean m_allowInternalWhitespace; | |||||
private String m_additionalInternalCharacters; | |||||
/** | |||||
* Construct a default name validator. | |||||
* Letters, digits and "_" are permitted as initial character. | |||||
* Letters, digits, whitespace and "_-." are permitted as internal characters. | |||||
* Surrounding whitespace is not permitted. | |||||
*/ | |||||
public DefaultNameValidator() | |||||
{ | |||||
this( false, true, "_", true, true, "_-." ); | |||||
} | |||||
/** | |||||
* Contstruct a NameValidator with the specified rules. | |||||
* @param allowSurroundingWhitespace | |||||
* specified if names are trimmed before checking | |||||
* @param allowInitialDigit | |||||
* specifies if digits are permitted as intial characters | |||||
* @param additionalInitialCharacters | |||||
* extra characters to allow as initial characters. | |||||
* @param allowInternalDigits | |||||
* specifies if digits are permitted as internal characters | |||||
* @param allowInternalWhitespace | |||||
* specifies if whitespace is permitted internally in names | |||||
* @param additionalInternalCharacters | |||||
* extra characters permitted in names | |||||
*/ | |||||
public DefaultNameValidator( final boolean allowSurroundingWhitespace, | |||||
final boolean allowInitialDigit, | |||||
final String additionalInitialCharacters, | |||||
final boolean allowInternalDigits, | |||||
final boolean allowInternalWhitespace, | |||||
final String additionalInternalCharacters ) | |||||
{ | |||||
setAllowSurroundingWhitespace( allowSurroundingWhitespace ); | |||||
setAllowInitialDigit( allowInitialDigit ); | |||||
setAdditionalInitialCharacters( additionalInitialCharacters ); | |||||
setAllowInternalDigits( allowInternalDigits ); | |||||
setAllowInternalWhitespace( allowInternalWhitespace ); | |||||
setAdditionalInternalCharacters( additionalInternalCharacters ); | |||||
} | |||||
/** | |||||
* Creates a valid name based on the supplied string value, removing invalid | |||||
* characters. If no valid characters are present, an exception is thrown. | |||||
* @param baseName the name used to construct the valid name | |||||
* @return a valid name based on the supplied name. | |||||
* @throws Exception if no valid name could be constructed. | |||||
*/ | |||||
public String makeValidName( final String baseName ) throws Exception | |||||
{ | |||||
final StringBuffer buffer = new StringBuffer( baseName ); | |||||
while( buffer.length() > 0 && !isValidInitialChar( buffer.charAt( 0 ) ) ) | |||||
{ | |||||
buffer.delete( 0, 1 ); | |||||
} | |||||
if( buffer.length() == 0 ) | |||||
{ | |||||
final String message = REZ.getString( "name.could-not-create.error", baseName ); | |||||
throw new Exception( message ); | |||||
} | |||||
for( int i = 1; i < buffer.length(); ) | |||||
{ | |||||
if( !isValidInternalChar( buffer.charAt( i ) ) ) | |||||
{ | |||||
buffer.delete( i, i + 1 ); | |||||
} | |||||
else | |||||
{ | |||||
i++; | |||||
} | |||||
} | |||||
return buffer.toString(); | |||||
} | |||||
/** | |||||
* @see NameValidator | |||||
*/ | |||||
public void validate( final String name ) throws Exception | |||||
{ | |||||
String testName = name; | |||||
// If surrounding whitespace is allowed, trim it. Otherwise, check. | |||||
if( m_allowSurroundingWhitespace ) | |||||
{ | |||||
testName = testName.trim(); | |||||
} | |||||
else | |||||
{ | |||||
checkSurroundingWhitespace( testName ); | |||||
} | |||||
// Zero-length name is invalid. | |||||
if( testName.length() == 0 ) | |||||
{ | |||||
final String message = REZ.getString( "name.zero-char-name.error" ); | |||||
throw new Exception( message ); | |||||
} | |||||
// Check first character. | |||||
final char initial = testName.charAt( 0 ); | |||||
checkInitialCharacter( initial, testName ); | |||||
// Check the rest of the characters. | |||||
for( int i = 1; i < testName.length(); i++ ) | |||||
{ | |||||
final char internal = testName.charAt( i ); | |||||
checkInternalCharacter( internal, testName ); | |||||
} | |||||
} | |||||
/** | |||||
* Checks if the supplied character is permitted as an internal character. | |||||
* @throws Exception if the character is not permitted | |||||
*/ | |||||
private void checkInternalCharacter( final char internal, final String name ) | |||||
throws Exception | |||||
{ | |||||
if( !isValidInternalChar( internal ) ) | |||||
{ | |||||
final String message = REZ.getString( "name.invalid-internal-char.error", | |||||
name, | |||||
describeValidInternalChars() ); | |||||
throw new Exception( message ); | |||||
} | |||||
} | |||||
/** | |||||
* Checks if the supplied character is permitted as an internal character. | |||||
* @throws Exception if the character is not permitted | |||||
*/ | |||||
private void checkInitialCharacter( final char initial, final String name ) | |||||
throws Exception | |||||
{ | |||||
if( !isValidInitialChar( initial ) ) | |||||
{ | |||||
final String message = REZ.getString( "name.invalid-initial-char.error", | |||||
name, | |||||
describeValidInitialChars() ); | |||||
throw new Exception( message ); | |||||
} | |||||
} | |||||
/** | |||||
* Checks the name for surrounding whitespace | |||||
* @throws Exception if surrounding whitespace is found | |||||
*/ | |||||
private void checkSurroundingWhitespace( final String testName ) | |||||
throws Exception | |||||
{ | |||||
if( testName.length() == 0 ) | |||||
{ | |||||
return; | |||||
} | |||||
if( Character.isWhitespace( testName.charAt( 0 ) ) || | |||||
Character.isWhitespace( testName.charAt( testName.length() - 1 ) ) ) | |||||
{ | |||||
final String message = | |||||
REZ.getString( "name.enclosing-whitespace.error", testName ); | |||||
throw new Exception( message ); | |||||
} | |||||
} | |||||
/** | |||||
* Determines if a character is allowed as the first character in a name. | |||||
* Valid characters are Letters, Digits, and defined initial characters ("_"). | |||||
* @param chr the character to be assessed | |||||
* @return <code>true</code> if the character can be the first character of a name | |||||
*/ | |||||
protected boolean isValidInitialChar( final char chr ) | |||||
{ | |||||
if( Character.isLetter( chr ) ) | |||||
{ | |||||
return true; | |||||
} | |||||
if( m_allowInitialDigit | |||||
&& Character.isDigit( chr ) ) | |||||
{ | |||||
return true; | |||||
} | |||||
if( m_additionalInitialCharacters.indexOf( chr ) != -1 ) | |||||
{ | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* Determines if a character is allowed as a non-initial character in a name. | |||||
* Valid characters are Letters, Digits, whitespace, and defined | |||||
* internal characters ("_-."). | |||||
* @param chr the character to be assessed | |||||
* @return <code>true</code> if the character can be included in a name | |||||
*/ | |||||
protected boolean isValidInternalChar( final char chr ) | |||||
{ | |||||
if( Character.isLetter( chr ) ) | |||||
{ | |||||
return true; | |||||
} | |||||
if( m_allowInternalDigits | |||||
&& Character.isDigit( chr ) ) | |||||
{ | |||||
return true; | |||||
} | |||||
if( m_allowInternalWhitespace | |||||
&& Character.isWhitespace( chr ) ) | |||||
{ | |||||
return true; | |||||
} | |||||
if( m_additionalInternalCharacters.indexOf( chr ) != -1 ) | |||||
{ | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* Builds a message detailing the valid initial characters. | |||||
*/ | |||||
protected String describeValidInitialChars() | |||||
{ | |||||
StringBuffer validChars = new StringBuffer( "letters" ); | |||||
if( m_allowInitialDigit ) | |||||
{ | |||||
validChars.append( ", digits" ); | |||||
} | |||||
validChars.append( ", and \"" ); | |||||
validChars.append( m_additionalInitialCharacters ); | |||||
validChars.append( "\"" ); | |||||
return validChars.toString(); | |||||
} | |||||
/** | |||||
* Builds a message detailing the valid internal characters. | |||||
*/ | |||||
protected String describeValidInternalChars() | |||||
{ | |||||
StringBuffer validChars = new StringBuffer( "letters" ); | |||||
if( m_allowInternalDigits ) | |||||
{ | |||||
validChars.append( ", digits" ); | |||||
} | |||||
if( m_allowInternalWhitespace ) | |||||
{ | |||||
validChars.append( ", whitespace" ); | |||||
} | |||||
validChars.append( ", and \"" ); | |||||
validChars.append( m_additionalInternalCharacters ); | |||||
validChars.append( "\"" ); | |||||
return validChars.toString(); | |||||
} | |||||
/** | |||||
* @param allowSurroundingWhitespace | |||||
* specified if names are trimmed before checking | |||||
*/ | |||||
public void setAllowSurroundingWhitespace( boolean allowSurroundingWhitespace ) | |||||
{ | |||||
m_allowSurroundingWhitespace = allowSurroundingWhitespace; | |||||
} | |||||
/** | |||||
* @param allowInitialDigit | |||||
* specifies if digits are permitted as intial characters | |||||
*/ | |||||
public void setAllowInitialDigit( boolean allowInitialDigit ) | |||||
{ | |||||
m_allowInitialDigit = allowInitialDigit; | |||||
} | |||||
/** | |||||
* @param additionalInitialCharacters | |||||
* extra characters to allow as initial characters. | |||||
*/ | |||||
public void setAdditionalInitialCharacters( String additionalInitialCharacters ) | |||||
{ | |||||
m_additionalInitialCharacters = additionalInitialCharacters; | |||||
} | |||||
/** | |||||
* @param allowInternalDigits | |||||
* specifies if digits are permitted as internal characters | |||||
*/ | |||||
public void setAllowInternalDigits( boolean allowInternalDigits ) | |||||
{ | |||||
m_allowInternalDigits = allowInternalDigits; | |||||
} | |||||
/** | |||||
* @param allowInternalWhitespace | |||||
* specifies if whitespace is permitted internally in names | |||||
*/ | |||||
public void setAllowInternalWhitespace( boolean allowInternalWhitespace ) | |||||
{ | |||||
m_allowInternalWhitespace = allowInternalWhitespace; | |||||
} | |||||
/** | |||||
* @param additionalInternalCharacters | |||||
* extra characters permitted in names | |||||
*/ | |||||
public void setAdditionalInternalCharacters( String additionalInternalCharacters ) | |||||
{ | |||||
m_additionalInternalCharacters = additionalInternalCharacters; | |||||
} | |||||
} |
@@ -1,46 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.model; | |||||
/** | |||||
* A dependency for a target. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class Dependency | |||||
{ | |||||
private final String m_projectName; | |||||
private final String m_targetName; | |||||
/** | |||||
* @param projectName The project containing the depended-on target. | |||||
* @param targetName The name of the depended-on target. | |||||
*/ | |||||
public Dependency( final String projectName, final String targetName ) | |||||
{ | |||||
m_projectName = projectName; | |||||
m_targetName = targetName; | |||||
} | |||||
/** | |||||
* @return The name of the project containing the depended-on target. | |||||
*/ | |||||
public String getProjectName() | |||||
{ | |||||
return m_projectName; | |||||
} | |||||
/** | |||||
* @return The name of the depended-on target. | |||||
*/ | |||||
public String getTargetName() | |||||
{ | |||||
return m_targetName; | |||||
} | |||||
} |
@@ -1,26 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.model; | |||||
/** | |||||
* Determines the validity of names used in projects. | |||||
* | |||||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface NameValidator | |||||
{ | |||||
/** | |||||
* Validates the supplied name, failing if it is not. | |||||
* | |||||
* @param name The name to be validated. | |||||
* @throws Exception is the supplied name is not valid. | |||||
*/ | |||||
void validate( String name ) | |||||
throws Exception; | |||||
} |
@@ -1,100 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.model; | |||||
import java.io.File; | |||||
/** | |||||
* Abstraction used to interact with projects. | |||||
* Implementations may choose to structure it anyway they choose. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface Project | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = Project.class.getName(); | |||||
/** Property which holds the name of currently executing project */ | |||||
String PROJECT = "myrmidon.project.name"; | |||||
// the name of currently executing project | |||||
//String PROJECT_FILE = "myrmidon.project.file"; | |||||
// the name of currently executing target | |||||
//String TARGET = "myrmidon.target.name"; | |||||
/** | |||||
* @return the project name. | |||||
* | |||||
* TODO: Determine if projects should carry their own name. Breaks IOC but | |||||
* Can be useful as project files embed own name (or should that be description). | |||||
*/ | |||||
String getProjectName(); | |||||
/** | |||||
* Get the imports for project. | |||||
* | |||||
* @return the imports | |||||
*/ | |||||
TypeLib[] getTypeLibs(); | |||||
/** | |||||
* Get names of projects referenced by this project. | |||||
* | |||||
* @return the names | |||||
*/ | |||||
String[] getProjectNames(); | |||||
/** | |||||
* Retrieve project referenced by this project. | |||||
* | |||||
* @param name the project name | |||||
* @return the Project or null if none by that name | |||||
*/ | |||||
Project getProject( String name ); | |||||
/** | |||||
* Get name of default target. | |||||
* | |||||
* @return the default target name | |||||
*/ | |||||
String getDefaultTargetName(); | |||||
/** | |||||
* Retrieve implicit target. | |||||
* The implicit target is top level tasks. | |||||
* Currently restricted to property tasks. | |||||
* | |||||
* @return the Target | |||||
*/ | |||||
Target getImplicitTarget(); | |||||
/** | |||||
* Retrieve a target by name. | |||||
* | |||||
* @param name the name of target | |||||
* @return the Target or null if no target exists with name | |||||
*/ | |||||
Target getTarget( String name ); | |||||
/** | |||||
* Retrieve names of all targets in project. | |||||
* | |||||
* @return the iterator of project names | |||||
*/ | |||||
String[] getTargetNames(); | |||||
/** | |||||
* Retrieve base directory of project. | |||||
* | |||||
* @return the projects base directory | |||||
*/ | |||||
File getBaseDirectory(); | |||||
} |
@@ -1,6 +0,0 @@ | |||||
# Name validation | |||||
name.zero-char-name.error=Name "" is invalid, as it contains no characters. | |||||
name.enclosing-whitespace.error=Name "{0}" is invalid, as it contains enclosing whitespace. | |||||
name.invalid-initial-char.error=Name "{0}" is invalid, as it begins with an illegal character. Names can start with {1}. | |||||
name.invalid-internal-char.error=Name "{0}" is invalid, as it contains an illegal character. Permitted name characters are {1}. | |||||
name.could-not-create.error=Could not valid name from "{0}". |
@@ -1,65 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.model; | |||||
import java.util.ArrayList; | |||||
import org.apache.avalon.framework.configuration.Configuration; | |||||
/** | |||||
* Targets in build file. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class Target | |||||
{ | |||||
private final ArrayList m_dependencies = new ArrayList(); | |||||
private final ArrayList m_tasks = new ArrayList(); | |||||
/** | |||||
* Constructs a target. | |||||
* @param tasks The task models for all tasks in this target. | |||||
* @param dependencies The dependencies for executing this target. | |||||
*/ | |||||
public Target( final Configuration[] tasks, | |||||
final Dependency[] dependencies ) | |||||
{ | |||||
for( int i = 0; i < tasks.length; i++ ) | |||||
{ | |||||
m_tasks.add( tasks[ i ] ); | |||||
} | |||||
if( null != dependencies ) | |||||
{ | |||||
for( int i = 0; i < dependencies.length; i++ ) | |||||
{ | |||||
m_dependencies.add( dependencies[ i ] ); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Get dependencies of target | |||||
* | |||||
* @return the dependency list | |||||
*/ | |||||
public final Dependency[] getDependencies() | |||||
{ | |||||
return (Dependency[])m_dependencies.toArray( new Dependency[ 0 ] ); | |||||
} | |||||
/** | |||||
* Get tasks in target | |||||
* | |||||
* @return the target list | |||||
*/ | |||||
public final Configuration[] getTasks() | |||||
{ | |||||
return (Configuration[])m_tasks.toArray( new Configuration[ 0 ] ); | |||||
} | |||||
} |
@@ -1,93 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.model; | |||||
/** | |||||
* Imports in a build file. | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class TypeLib | |||||
{ | |||||
//Name of library (this is location independent) | |||||
private final String m_library; | |||||
//Do we need this?? | |||||
//private final String m_namespace; | |||||
//The role of object to be imported | |||||
private final String m_role; | |||||
//The name of type instance | |||||
private final String m_name; | |||||
/** | |||||
* Create a import for a complete library. | |||||
* @param library The name of the library to import. | |||||
*/ | |||||
public TypeLib( final String library ) | |||||
{ | |||||
this( library, null, null ); | |||||
} | |||||
/** | |||||
* Create an import for a single type from a library. | |||||
* @param library The library containing the type. | |||||
* @param role The role for the imported type. | |||||
* @param name The name of the imported type. | |||||
*/ | |||||
public TypeLib( final String library, final String role, final String name ) | |||||
{ | |||||
m_library = library; | |||||
m_role = role; | |||||
m_name = name; | |||||
//If only one of name or type is null, throw an exception | |||||
if( null == m_role || null == m_name ) | |||||
{ | |||||
if( null != m_role || null != m_name ) | |||||
{ | |||||
throw new IllegalArgumentException( "Can not have an import that specifies " + | |||||
"only one of; name or role" ); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Get role | |||||
* | |||||
* @return the role | |||||
*/ | |||||
public final String getRole() | |||||
{ | |||||
return m_role; | |||||
} | |||||
/** | |||||
* Get name of imported | |||||
* | |||||
* @return the name | |||||
*/ | |||||
public final String getName() | |||||
{ | |||||
return m_name; | |||||
} | |||||
/** | |||||
* Get name of library | |||||
* | |||||
* @return the library name | |||||
*/ | |||||
public final String getLibrary() | |||||
{ | |||||
return m_library; | |||||
} | |||||
} | |||||
@@ -1,119 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.property; | |||||
import java.util.Map; | |||||
import java.util.HashMap; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
import org.apache.avalon.excalibur.i18n.Resources; | |||||
/** | |||||
* A simple unscoped, unsynchronized property store which is backed by a Map. | |||||
* | |||||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public class MapPropertyStore | |||||
implements PropertyStore | |||||
{ | |||||
private static final Resources REZ = | |||||
ResourceManager.getPackageResources( MapPropertyStore.class ); | |||||
private final Map m_properties = new HashMap(); | |||||
/** | |||||
* Creates an empty store. | |||||
*/ | |||||
public MapPropertyStore() | |||||
{ | |||||
} | |||||
/** | |||||
* Creates a store containing the given properties. | |||||
*/ | |||||
public MapPropertyStore( final Map properties ) | |||||
{ | |||||
m_properties.putAll( properties ); | |||||
} | |||||
/** | |||||
* Return <code>true</code> if the specified property is set. | |||||
* | |||||
* @param name the name of property | |||||
*/ | |||||
public boolean isPropertySet( final String name ) | |||||
{ | |||||
return m_properties.containsKey( name ); | |||||
} | |||||
/** | |||||
* Retrieve the value of specified property. | |||||
* | |||||
* @param name the name of the property | |||||
* @return the value of the property. Never returns null. | |||||
* @throws TaskException if there is no such property, or on error | |||||
* retrieving property, such as an invalid property name. | |||||
*/ | |||||
public Object getProperty( final String name ) | |||||
throws TaskException | |||||
{ | |||||
final Object value = m_properties.get( name ); | |||||
if( value == null ) | |||||
{ | |||||
final String message = REZ.getString( "unknown-property.error", name ); | |||||
throw new TaskException( message ); | |||||
} | |||||
return value; | |||||
} | |||||
/** | |||||
* Retrieve a copy of all the properties that are "in-scope" | |||||
* for store. | |||||
* | |||||
* @return a copy of all the properties that are "in-scope" | |||||
* for store. | |||||
* @throws TaskException if theres an error retrieving propertys | |||||
*/ | |||||
public Map getProperties() | |||||
throws TaskException | |||||
{ | |||||
return new HashMap( m_properties ); | |||||
} | |||||
/** | |||||
* Set the property with specified name to specified value. | |||||
* The specific implementation will apply various rules | |||||
* before setting the property. | |||||
* | |||||
* @param name the name of property | |||||
* @param value the value of property | |||||
* @throws TaskException if property can not be set | |||||
*/ | |||||
public void setProperty( String name, Object value ) | |||||
throws TaskException | |||||
{ | |||||
m_properties.put( name, value ); | |||||
} | |||||
/** | |||||
* Return a child PropertyStore with specified name. | |||||
* This is to allow support for scoped stores. However a | |||||
* store may choose to be unscoped and just return a | |||||
* reference to itself. | |||||
* | |||||
* @param name the name of child store | |||||
* @return the child store | |||||
* @throws TaskException if theres an error creating child store | |||||
*/ | |||||
public PropertyStore createChildStore( String name ) | |||||
throws TaskException | |||||
{ | |||||
return this; | |||||
} | |||||
} |
@@ -1,41 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.property; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.myrmidon.api.TaskContext; | |||||
/** | |||||
* | |||||
* Provides a service for the resolution of property identifiers within | |||||
* String content. | |||||
* | |||||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
* @version $Revision$ $Date$ | |||||
* | |||||
* @ant:role shorthand="property-resolver" | |||||
*/ | |||||
public interface PropertyResolver | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = PropertyResolver.class.getName(); | |||||
/** | |||||
* Resolve a string property. This evaluates all property | |||||
* substitutions based on specified contex. | |||||
* Rules used for property resolution are implementation dependent. | |||||
* | |||||
* @param value the value to resolve, which may contain property identifiers | |||||
* @param context the set of properties to resolve against. | |||||
* @return the resolved content | |||||
* @exception TaskException if an error occurs | |||||
*/ | |||||
Object resolveProperties( final String value, | |||||
final TaskContext context ) | |||||
throws TaskException; | |||||
} |
@@ -1,86 +0,0 @@ | |||||
/* | |||||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
* | |||||
* This software is published under the terms of the Apache Software License | |||||
* version 1.1, a copy of which has been included with this distribution in | |||||
* the LICENSE.txt file. | |||||
*/ | |||||
package org.apache.myrmidon.interfaces.property; | |||||
import java.util.Map; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
/** | |||||
* This component stores and manages properties. It is also | |||||
* responsible for instituting the various policies regarding | |||||
* propertys. ie It will enforce rules regarding | |||||
* | |||||
* <ul> | |||||
* <li>Valid property names?</li> | |||||
* <li>Are propertys mutable?</li> | |||||
* <li>Are propertys scoped?</li> | |||||
* <li>Is mapping between name and value correct?</li> | |||||
* </ul> | |||||
* | |||||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
* @version $Revision$ $Date$ | |||||
*/ | |||||
public interface PropertyStore | |||||
{ | |||||
/** Role name for this interface. */ | |||||
String ROLE = PropertyStore.class.getName(); | |||||
/** | |||||
* Set the property with specified name to specified value. | |||||
* The specific implementation will apply various rules | |||||
* before setting the property. | |||||
* | |||||
* @param name the name of property | |||||
* @param value the value of property | |||||
* @throws TaskException if property can not be set | |||||
*/ | |||||
void setProperty( String name, Object value ) | |||||
throws TaskException; | |||||
/** | |||||
* Return <code>true</code> if the specified property is set. | |||||
* | |||||
* @param name the name of property | |||||
*/ | |||||
boolean isPropertySet( String name ); | |||||
/** | |||||
* Retrieve the value of specified property. | |||||
* | |||||
* @param name the name of the property | |||||
* @return the value of the property. Never returns null. | |||||
* @throws TaskException if there is no such property, or on error | |||||
* retrieving property, such as an invalid property name. | |||||
*/ | |||||
Object getProperty( String name ) | |||||
throws TaskException; | |||||
/** | |||||
* Retrieve a copy of all the properties that are "in-scope" | |||||
* for store. | |||||
* | |||||
* @return a copy of all the properties that are "in-scope" | |||||
* for store. | |||||
* @throws TaskException if theres an error retrieving propertys | |||||
*/ | |||||
Map getProperties() | |||||
throws TaskException; | |||||
/** | |||||
* Return a child PropertyStore with specified name. | |||||
* This is to allow support for scoped stores. However a | |||||
* store may choose to be unscoped and just return a | |||||
* reference to itself. | |||||
* | |||||
* @param name the name of child store | |||||
* @return the child store | |||||
* @throws TaskException if theres an error creating child store | |||||
*/ | |||||
PropertyStore createChildStore( String name ) | |||||
throws TaskException; | |||||
} |