Note this wont run until we break out container-api.jar and place in lib/ so that the runtime/ant1compat classes will work at runtime. At the moment they will compile ma no run. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272374 13f79535-47bb-0310-9956-ffa450edef68master
@@ -14,7 +14,7 @@ | |||
<path id="project.class.path"> | |||
<pathelement location="build/classes"/> | |||
<fileset dir="lib"> | |||
<include name="*.jar"/> | |||
<include name="**/*.jar"/> | |||
</fileset> | |||
</path> | |||
@@ -251,9 +251,7 @@ Legal: | |||
<src path="${build.src}" /> | |||
--> | |||
<patternset refid="myrmidon-launcher.include"/> | |||
<patternset refid="myrmidon-framework.include"/> | |||
<patternset refid="myrmidon-container.include"/> | |||
<patternset refid="ant1.todo.include"/> | |||
<patternset refid="selftest.include"/> | |||
<patternset refid="selftest-extension1.include"/> | |||
@@ -269,22 +267,12 @@ Legal: | |||
</target> | |||
<target name="setup-patterns" depends="check_for_optional_packages"> | |||
<patternset id="myrmidon-launcher.include"> | |||
<include name="org/apache/myrmidon/launcher/**" /> | |||
</patternset> | |||
<patternset id="myrmidon-framework.include"> | |||
<include name="org/apache/myrmidon/interfaces/**" /> | |||
<include name="org/apache/myrmidon/framework/**" /> | |||
</patternset> | |||
<patternset id="myrmidon-container.include"> | |||
<include name="org/apache/myrmidon/components/**" /> | |||
<include name="org/apache/myrmidon/frontends/**" /> | |||
<include name="org/apache/myrmidon/*" /> | |||
<exclude name="**/TransformingProjectBuilder.java" unless="trax.present"/> | |||
</patternset> | |||
<property name="ant.package" value="org/apache/tools/todo"/> | |||
<property name="taskdefs.package" value="${ant.package}/taskdefs"/> | |||
<property name="antlib.package" value="org/apache/antlib"/> | |||
@@ -390,14 +378,6 @@ Legal: | |||
</fileset> | |||
</antlib-descriptor> | |||
<antlib-descriptor libName="container" | |||
destdir="${gen.dir}" | |||
classpathref="project.class.path"> | |||
<fileset dir="${java.dir}"> | |||
<patternset refid="myrmidon-container.include"/> | |||
</fileset> | |||
</antlib-descriptor> | |||
<antlib-descriptor libName="selftest" | |||
destdir="${gen.dir}" | |||
classpathref="project.class.path"> | |||
@@ -422,20 +402,6 @@ Legal: | |||
<mkdir dir="${build.lib}"/> | |||
<mkdir dir="${build.ext}"/> | |||
<jar jarfile="${build.bin}/myrmidon-launcher.jar" | |||
basedir="${build.classes}" | |||
manifest="${manifest.dir}/myrmidon-launcher.mf"> | |||
<patternset refid="myrmidon-launcher.include"/> | |||
</jar> | |||
<antlib-jar jarfile="${build.bin}/lib/myrmidon-container.jar" | |||
basedir="${build.classes}" | |||
manifest="${manifest.dir}/myrmidon-container.mf" | |||
rolesDescriptor="${gen.dir}/container-ant-roles.xml" | |||
descriptor="${gen.dir}/container-ant-descriptor.xml" > | |||
<patternset refid="myrmidon-container.include"/> | |||
</antlib-jar> | |||
<antlib-jar jarfile="${build.lib}/myrmidon-framework.jar" | |||
basedir="${build.classes}" | |||
manifest="${manifest.dir}/myrmidon-api.mf" | |||
@@ -1,179 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.aspect; | |||
import java.util.HashMap; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.activity.Initializable; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.myrmidon.api.Task; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.aspects.AspectHandler; | |||
import org.apache.myrmidon.aspects.NoopAspectHandler; | |||
import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||
/** | |||
* Manage and propogate Aspects. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultAspectManager | |||
implements AspectManager, Initializable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultAspectManager.class ); | |||
private HashMap m_aspectMap = new HashMap(); | |||
private AspectHandler[] m_aspects = new AspectHandler[ 0 ]; | |||
private String[] m_names = new String[ 0 ]; | |||
public void initialize() | |||
throws Exception | |||
{ | |||
///UGLY HACK!!!! | |||
addAspectHandler( "ant", new NoopAspectHandler() ); | |||
addAspectHandler( "doc", new NoopAspectHandler() ); | |||
} | |||
public synchronized void addAspectHandler( final String name, final AspectHandler handler ) | |||
throws TaskException | |||
{ | |||
m_aspectMap.put( name, handler ); | |||
rebuildArrays(); | |||
} | |||
public synchronized void removeAspectHandler( final String name ) | |||
throws TaskException | |||
{ | |||
final AspectHandler entry = (AspectHandler)m_aspectMap.remove( name ); | |||
if( null == entry ) | |||
{ | |||
final String message = REZ.getString( "no.aspect", name ); | |||
throw new TaskException( message ); | |||
} | |||
rebuildArrays(); | |||
} | |||
private void rebuildArrays() | |||
{ | |||
m_aspects = (AspectHandler[])m_aspectMap.values().toArray( m_aspects ); | |||
m_names = (String[])m_aspectMap.keySet().toArray( m_names ); | |||
} | |||
public String[] getNames() | |||
{ | |||
return m_names; | |||
} | |||
public void dispatchAspectSettings( final String name, | |||
final Parameters parameters, | |||
final Configuration[] elements ) | |||
throws TaskException | |||
{ | |||
final AspectHandler handler = (AspectHandler)m_aspectMap.get( name ); | |||
if( null == handler ) | |||
{ | |||
final String message = REZ.getString( "no.aspect", name ); | |||
throw new TaskException( message ); | |||
} | |||
handler.aspectSettings( parameters, elements ); | |||
} | |||
public Configuration preCreate( final Configuration configuration ) | |||
throws TaskException | |||
{ | |||
Configuration model = configuration; | |||
final AspectHandler[] aspects = m_aspects; | |||
for( int i = 0; i < aspects.length; i++ ) | |||
{ | |||
model = aspects[ i ].preCreate( model ); | |||
} | |||
return model; | |||
} | |||
public void aspectSettings( final Parameters parameters, final Configuration[] elements ) | |||
throws TaskException | |||
{ | |||
final String message = REZ.getString( "no.settings" ); | |||
throw new UnsupportedOperationException( message ); | |||
} | |||
public void postCreate( final Task task ) | |||
throws TaskException | |||
{ | |||
final AspectHandler[] aspects = m_aspects; | |||
for( int i = 0; i < aspects.length; i++ ) | |||
{ | |||
aspects[ i ].postCreate( task ); | |||
} | |||
} | |||
public void preLogEnabled( final Logger logger ) | |||
throws TaskException | |||
{ | |||
final AspectHandler[] aspects = m_aspects; | |||
for( int i = 0; i < aspects.length; i++ ) | |||
{ | |||
aspects[ i ].preLogEnabled( logger ); | |||
} | |||
} | |||
public void preConfigure( final Configuration taskModel ) | |||
throws TaskException | |||
{ | |||
final AspectHandler[] aspects = m_aspects; | |||
for( int i = 0; i < aspects.length; i++ ) | |||
{ | |||
aspects[ i ].preConfigure( taskModel ); | |||
} | |||
} | |||
public void preExecute() | |||
throws TaskException | |||
{ | |||
final AspectHandler[] aspects = m_aspects; | |||
for( int i = 0; i < aspects.length; i++ ) | |||
{ | |||
aspects[ i ].preExecute(); | |||
} | |||
} | |||
public void preDestroy() | |||
throws TaskException | |||
{ | |||
final AspectHandler[] aspects = m_aspects; | |||
for( int i = 0; i < aspects.length; i++ ) | |||
{ | |||
aspects[ i ].preDestroy(); | |||
} | |||
} | |||
public boolean error( final TaskException te ) | |||
throws TaskException | |||
{ | |||
final AspectHandler[] aspects = m_aspects; | |||
for( int i = 0; i < aspects.length; i++ ) | |||
{ | |||
final boolean isError = aspects[ i ].error( te ); | |||
if( isError ) | |||
{ | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} |
@@ -1,2 +0,0 @@ | |||
no.aspect=No such aspect with name {0}. | |||
no.settings=Can not provide Settings to AspectManager. |
@@ -1,227 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.builder; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.util.Properties; | |||
import javax.xml.parsers.SAXParser; | |||
import javax.xml.parsers.SAXParserFactory; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||
import org.apache.avalon.framework.parameters.Parameterizable; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.XMLReader; | |||
/** | |||
* Default implementation to construct project from a build file. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
* @ant.type type="project-builder" name="ati" | |||
*/ | |||
public class ATIProjectBuilder | |||
extends DefaultProjectBuilder | |||
implements Parameterizable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( ATIProjectBuilder.class ); | |||
private Parameters m_parameters; | |||
public void parameterize( final Parameters parameters ) | |||
{ | |||
m_parameters = parameters; | |||
} | |||
protected void process( final URL sourceID, | |||
final SAXConfigurationHandler handler ) | |||
throws Exception | |||
{ | |||
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||
final SAXParser saxParser = saxParserFactory.newSAXParser(); | |||
final XMLReader reader = saxParser.getXMLReader(); | |||
reader.setFeature( "http://xml.org/sax/features/validation", false ); | |||
reader.setErrorHandler( handler ); | |||
final ReactorPIHandler reactorHandler = new ReactorPIHandler(); | |||
reader.setContentHandler( reactorHandler ); | |||
try | |||
{ | |||
reader.parse( sourceID.toString() ); | |||
} | |||
catch( final StopParsingException spe ) | |||
{ | |||
//Ignore me | |||
} | |||
Transformer transformer = null; | |||
final int size = reactorHandler.getPICount(); | |||
for( int i = 0; i < size; i++ ) | |||
{ | |||
final String target = reactorHandler.getTarget( i ); | |||
final String data = reactorHandler.getData( i ); | |||
if( target.equals( "xsl-param" ) ) | |||
{ | |||
handleParameter( data ); | |||
} | |||
else if( target.equals( "xsl-params" ) ) | |||
{ | |||
handleParameters( data, sourceID ); | |||
} | |||
else if( target.equals( "xsl-stylesheet" ) ) | |||
{ | |||
if( null != transformer ) | |||
{ | |||
final String message = REZ.getString( "ati.two.stylesheet.pis" ); | |||
throw new SAXException( message ); | |||
} | |||
final TransformerFactory factory = TransformerFactory.newInstance(); | |||
final String stylesheet = getStylesheet( data, sourceID ); | |||
transformer = factory.newTransformer( new StreamSource( stylesheet ) ); | |||
} | |||
} | |||
if( null == transformer ) | |||
{ | |||
reader.setContentHandler( handler ); | |||
reader.parse( sourceID.toString() ); | |||
} | |||
else | |||
{ | |||
final String[] names = m_parameters.getNames(); | |||
for( int i = 0; i < names.length; i++ ) | |||
{ | |||
final String name = names[ i ]; | |||
final String value = m_parameters.getParameter( name ); | |||
transformer.setParameter( name, value ); | |||
} | |||
final SAXResult result = new SAXResult( handler ); | |||
transformer.transform( new StreamSource( sourceID.toString() ), result ); | |||
//transformer.transform( new StreamSource( sourceID.toString() ), | |||
//new StreamResult( System.out ) ); | |||
} | |||
} | |||
private void handleParameter( final String data ) | |||
throws SAXException | |||
{ | |||
int index = data.indexOf( '\"' ); | |||
if( -1 == index ) | |||
{ | |||
final String message = REZ.getString( "ati.param.error" ); | |||
throw new SAXException( message ); | |||
} | |||
index = data.indexOf( '\"', index + 1 ); | |||
if( -1 == index ) | |||
{ | |||
final String message = REZ.getString( "ati.param.error" ); | |||
throw new SAXException( message ); | |||
} | |||
//split between two "attributes" occurs on index | |||
final String[] name = parseAttribute( data.substring( 0, index + 1 ) ); | |||
final String[] value = parseAttribute( data.substring( index + 1 ).trim() ); | |||
if( !name[ 0 ].equals( "name" ) || !value[ 0 ].equals( "value" ) ) | |||
{ | |||
final String message = REZ.getString( "ati.param.error" ); | |||
throw new SAXException( message ); | |||
} | |||
m_parameters.setParameter( name[ 1 ], value[ 1 ] ); | |||
} | |||
private void handleParameters( final String data, final URL baseSource ) | |||
throws SAXException | |||
{ | |||
final String[] params = parseAttribute( data ); | |||
if( !params[ 0 ].equals( "location" ) ) | |||
{ | |||
final String message = REZ.getString( "ati.params.error" ); | |||
throw new SAXException( message ); | |||
} | |||
try | |||
{ | |||
final Properties properties = new Properties(); | |||
final URL url = new URL( baseSource, params[ 1 ] ); | |||
final InputStream input = url.openStream(); | |||
properties.load( input ); | |||
final Parameters parameters = Parameters.fromProperties( properties ); | |||
m_parameters.merge( parameters ); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "ati.loading-params.error", params[ 1 ], e ); | |||
throw new SAXException( message ); | |||
} | |||
} | |||
private String getStylesheet( final String data, final URL baseSource ) | |||
throws SAXException | |||
{ | |||
final String[] stylesheet = parseAttribute( data ); | |||
if( !stylesheet[ 0 ].equals( "href" ) ) | |||
{ | |||
final String message = REZ.getString( "ati.style.error" ); | |||
throw new SAXException( message ); | |||
} | |||
try | |||
{ | |||
return new URL( baseSource, stylesheet[ 1 ] ).toString(); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = | |||
REZ.getString( "ati.loading-style.error", stylesheet[ 1 ], e ); | |||
throw new SAXException( message ); | |||
} | |||
} | |||
private String[] parseAttribute( final String data ) | |||
throws SAXException | |||
{ | |||
//name="value" | |||
int index = data.indexOf( '=' ); | |||
if( -1 == index ) | |||
{ | |||
final String message = REZ.getString( "ati.attribue-expected.error", data ); | |||
throw new SAXException( message ); | |||
} | |||
final int size = data.length(); | |||
if( '\"' != data.charAt( index + 1 ) || | |||
'\"' != data.charAt( size - 1 ) || | |||
size - 1 == index ) | |||
{ | |||
final String message = | |||
REZ.getString( "ati.attribue-unquoted.error", data.substring( 0, index ) ); | |||
throw new SAXException( message ); | |||
} | |||
final String[] result = new String[ 2 ]; | |||
result[ 0 ] = data.substring( 0, index ); | |||
result[ 1 ] = data.substring( index + 2, size - 1 ); | |||
return result; | |||
} | |||
} |
@@ -1,247 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.builder; | |||
import java.util.HashSet; | |||
import java.util.Set; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.DefaultConfiguration; | |||
import org.apache.myrmidon.interfaces.builder.ProjectException; | |||
/** | |||
* A simple ProjectBuilder, which programmatically converts an Ant1 Project | |||
* configuration into a Myrmidon one. | |||
* | |||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
* @version $Revision$ $Date$ | |||
* | |||
* @ant.type type="project-builder" name="xml" | |||
* @ant.type type="project-builder" name="ant" | |||
* @ant.type type="project-builder" name="default" | |||
*/ | |||
public class ConvertingProjectBuilder | |||
extends DefaultProjectBuilder | |||
{ | |||
private static final String VERSION_ATTRIBUTE = "version"; | |||
/** | |||
* Builds a Configuration from an Ant1 project file, converting it | |||
* into a valid Myrmidon Project. | |||
* @param systemID the xml Systemid of the project file. | |||
* @return the configured project | |||
* @throws ProjectException if an error occurs parsing the project file | |||
*/ | |||
protected Configuration parseProject( final String systemID ) | |||
throws ProjectException | |||
{ | |||
final Configuration originalConfig = super.parseProject( systemID ); | |||
// Check the version, if it's present, just use this config. | |||
// TODO: check for version < 2.0 | |||
if( originalConfig.getAttribute( VERSION_ATTRIBUTE, null ) != null ) | |||
{ | |||
return originalConfig; | |||
} | |||
// Convert the config by prepending "ant1." on tasks, | |||
// and using <if> tasks instead of target 'if=' and 'unless=' | |||
final DefaultConfiguration newConfig = copyConfiguration( originalConfig ); | |||
// Put a new version attribute. | |||
newConfig.setAttribute( VERSION_ATTRIBUTE, "2.0" ); | |||
// Copy the remaining attributes. | |||
final Set omitAttributes = new HashSet(); | |||
omitAttributes.add( VERSION_ATTRIBUTE ); | |||
copyAttributes( originalConfig, newConfig, omitAttributes ); | |||
// Now copy/convert the children | |||
final Configuration[] children = originalConfig.getChildren(); | |||
for( int i = 0; i < children.length; i++ ) | |||
{ | |||
final Configuration child = children[ i ]; | |||
if( child.getName().equals( "target" ) ) | |||
{ | |||
newConfig.addChild( convertTarget( child ) ); | |||
} | |||
else | |||
{ | |||
newConfig.addChild( convertTask( child ) ); | |||
} | |||
} | |||
return newConfig; | |||
} | |||
/** | |||
* Converts Configuration for an Ant1 Target into a Myrmidon version. | |||
* @param originalTarget The Ant1 Target | |||
* @return the converted target | |||
*/ | |||
private Configuration convertTarget( final Configuration originalTarget ) | |||
{ | |||
final DefaultConfiguration newTarget = copyConfiguration( originalTarget ); | |||
// Copy all attributes except 'if' and 'unless' | |||
final Set omitAttributes = new HashSet(); | |||
omitAttributes.add( "if" ); | |||
omitAttributes.add( "unless" ); | |||
copyAttributes( originalTarget, newTarget, omitAttributes ); | |||
DefaultConfiguration containerElement = newTarget; | |||
// For 'if="prop-name"', replace with <if> task. | |||
final String ifAttrib = originalTarget.getAttribute( "if", null ); | |||
if ( ifAttrib != null ) | |||
{ | |||
final DefaultConfiguration ifElement = | |||
buildIfElement( ifAttrib, false, originalTarget.getLocation() ); | |||
containerElement.addChild( ifElement ); | |||
// Treat the ifElement as the enclosing target. | |||
containerElement = ifElement; | |||
} | |||
// For 'unless="prop-name"', replace with <if> task (negated). | |||
final String unlessAttrib = originalTarget.getAttribute( "unless", null ); | |||
if ( unlessAttrib != null ) | |||
{ | |||
final DefaultConfiguration unlessElement = | |||
buildIfElement( unlessAttrib, true, originalTarget.getLocation() ); | |||
containerElement.addChild( unlessElement ); | |||
// Treat the unlessElement as the enclosing target. | |||
containerElement = unlessElement; | |||
} | |||
// Now copy in converted tasks. | |||
final Configuration[] tasks = originalTarget.getChildren(); | |||
for( int i = 0; i < tasks.length; i++ ) | |||
{ | |||
containerElement.addChild( convertTask( tasks[ i ] ) ); | |||
} | |||
return newTarget; | |||
} | |||
/** | |||
* Builds configuration for an <if> task, to replace a "if" or "unless" | |||
* attribute on a Ant1 target. | |||
* @param ifProperty the name of the property from the Ant1 attribute. | |||
* @param unless if the attribute is actually an "unless" attribute. | |||
* @param location the configuration location to use | |||
* @return The configuration for an <if> task | |||
*/ | |||
private DefaultConfiguration buildIfElement( final String ifProperty, | |||
final boolean unless, | |||
final String location ) | |||
{ | |||
// <if> | |||
// <condition> | |||
// <is-set property="prop-name"/> | |||
// </condition> | |||
// .. tasks | |||
// </if> | |||
final DefaultConfiguration isSetElement = | |||
new DefaultConfiguration( "is-set", location ); | |||
isSetElement.setAttribute( "property", ifProperty ); | |||
final DefaultConfiguration conditionElement = | |||
new DefaultConfiguration( "condition", location ); | |||
if ( unless ) | |||
{ | |||
// Surround <is-set> with <not> | |||
final DefaultConfiguration notElement = | |||
new DefaultConfiguration( "not", location ); | |||
notElement.addChild( isSetElement ); | |||
conditionElement.addChild( notElement ); | |||
} | |||
else | |||
{ | |||
conditionElement.addChild( isSetElement ); | |||
} | |||
final DefaultConfiguration ifElement = | |||
new DefaultConfiguration( "if", location ); | |||
ifElement.addChild( conditionElement ); | |||
return ifElement; | |||
} | |||
/** | |||
* Converts Configuration for an Ant1 Task into a Myrmidon version. | |||
* @param originalTask The Ant1 Task | |||
* @return the converted task | |||
*/ | |||
private Configuration convertTask( final Configuration originalTask ) | |||
{ | |||
// Create a new configuration with the "ant1." prefix. | |||
final String newTaskName = "ant1." + originalTask.getName(); | |||
final DefaultConfiguration newTask = | |||
new DefaultConfiguration( newTaskName, originalTask.getLocation() ); | |||
// Copy all attributes and elements of the task. | |||
copyAttributes( originalTask, newTask, new HashSet() ); | |||
copyChildren( originalTask, newTask ); | |||
return newTask; | |||
} | |||
/** | |||
* Copies all child elements from one configuration to another | |||
* @param from Configuration to copy from | |||
* @param to Configuration to copy to | |||
*/ | |||
private void copyChildren( final Configuration from, | |||
final DefaultConfiguration to ) | |||
{ | |||
final Configuration[] children = from.getChildren(); | |||
for( int i = 0; i < children.length; i++ ) | |||
{ | |||
to.addChild( children[ i ] ); | |||
} | |||
} | |||
/** | |||
* Copies all attributes from one configuration to another, excluding | |||
* specified attribute names. | |||
* @param from Configuration to copy from | |||
* @param to Configuration to copy to | |||
* @param omitAttributes a Set of attribute names to exclude | |||
*/ | |||
private void copyAttributes( final Configuration from, | |||
final DefaultConfiguration to, | |||
final Set omitAttributes ) | |||
{ | |||
// Copy other attributes | |||
final String[] attribs = from.getAttributeNames(); | |||
for( int i = 0; i < attribs.length; i++ ) | |||
{ | |||
final String name = attribs[ i ]; | |||
if( omitAttributes.contains( name ) ) | |||
{ | |||
continue; | |||
} | |||
final String value = from.getAttribute( name, "" ); | |||
to.setAttribute( name, value ); | |||
} | |||
} | |||
/** | |||
* Creates a DefaultConfiguration with the same name and location as | |||
* the one supplied. | |||
* @param originalConfig the COnfiguration to copy. | |||
* @return the new Configuration | |||
*/ | |||
private DefaultConfiguration copyConfiguration( final Configuration originalConfig ) | |||
{ | |||
return new DefaultConfiguration( originalConfig.getName(), | |||
originalConfig.getLocation() ); | |||
} | |||
} |
@@ -1,229 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.builder; | |||
import java.io.File; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.model.Target; | |||
import org.apache.myrmidon.interfaces.model.TypeLib; | |||
/** | |||
* Default project implementation. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultProject | |||
implements Project | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultProject.class ); | |||
///The imports | |||
private final ArrayList m_imports = new ArrayList(); | |||
///The projects refferred to by this project | |||
private final HashMap m_projects = new HashMap(); | |||
///The targets contained by this project | |||
private final HashMap m_targets = new HashMap(); | |||
///The implicit target (not present in m_targets) | |||
private Target m_implicitTarget; | |||
///The name of the default target | |||
private String m_defaultTarget; | |||
///The base directory of project | |||
private File m_baseDirectory; | |||
///The project name | |||
private String m_name; | |||
/** | |||
* @return the project name. | |||
*/ | |||
public String getProjectName() | |||
{ | |||
return m_name; | |||
} | |||
/** | |||
* Sets the project name. | |||
* @param name the project name | |||
*/ | |||
public void setProjectName( String name ) | |||
{ | |||
m_name = name; | |||
} | |||
/** | |||
* Get the imports for project. | |||
* | |||
* @return the imports | |||
*/ | |||
public TypeLib[] getTypeLibs() | |||
{ | |||
return (TypeLib[])m_imports.toArray( new TypeLib[ 0 ] ); | |||
} | |||
/** | |||
* Get names of projects referred to by this project. | |||
* | |||
* @return the names | |||
*/ | |||
public String[] getProjectNames() | |||
{ | |||
return (String[])m_projects.keySet().toArray( new String[ 0 ] ); | |||
} | |||
/** | |||
* Retrieve project reffered to by this project. | |||
* | |||
* @param name the project name | |||
* @return the Project or null if none by that name | |||
*/ | |||
public Project getProject( final String name ) | |||
{ | |||
return (Project)m_projects.get( name ); | |||
} | |||
/** | |||
* Retrieve base directory of project. | |||
* | |||
* @return the projects base directory | |||
*/ | |||
public final File getBaseDirectory() | |||
{ | |||
return m_baseDirectory; | |||
} | |||
/** | |||
* Retrieve implicit target. | |||
* The implicit target contains all the top level tasks. | |||
* | |||
* @return the Target | |||
*/ | |||
public final Target getImplicitTarget() | |||
{ | |||
return m_implicitTarget; | |||
} | |||
/** | |||
* Set ImplicitTarget. | |||
* | |||
* @param target the implicit target | |||
*/ | |||
public final void setImplicitTarget( final Target target ) | |||
{ | |||
m_implicitTarget = target; | |||
} | |||
/** | |||
* Retrieve a target by name. | |||
* | |||
* @param targetName the name of target | |||
* @return the Target or null if no target exists with name | |||
*/ | |||
public final Target getTarget( final String targetName ) | |||
{ | |||
return (Target)m_targets.get( targetName ); | |||
} | |||
/** | |||
* Get name of default target. | |||
* | |||
* @return the default target name | |||
*/ | |||
public final String getDefaultTargetName() | |||
{ | |||
return m_defaultTarget; | |||
} | |||
/** | |||
* Retrieve names of all targets in project. | |||
* | |||
* @return an array target names | |||
*/ | |||
public final String[] getTargetNames() | |||
{ | |||
return (String[])m_targets.keySet().toArray( new String[ 0 ] ); | |||
} | |||
/** | |||
* Set DefaultTargetName. | |||
* | |||
* @param defaultTarget the default target name | |||
*/ | |||
public final void setDefaultTargetName( final String defaultTarget ) | |||
{ | |||
m_defaultTarget = defaultTarget; | |||
} | |||
/** | |||
* Sets the project base directory. | |||
* @param baseDirectory the base directory for the project | |||
*/ | |||
public final void setBaseDirectory( final File baseDirectory ) | |||
{ | |||
m_baseDirectory = baseDirectory; | |||
} | |||
/** | |||
* Adds a type library import to the project. | |||
* @param typeLib the type library | |||
*/ | |||
public final void addTypeLib( final TypeLib typeLib ) | |||
{ | |||
m_imports.add( typeLib ); | |||
} | |||
/** | |||
* Add a target. | |||
* | |||
* @param name the name of target | |||
* @param target the Target | |||
* @exception IllegalArgumentException if target already exists with same name | |||
*/ | |||
public final void addTarget( final String name, final Target target ) | |||
{ | |||
if( null != m_targets.get( name ) ) | |||
{ | |||
final String message = REZ.getString( "duplicate-target.error", name ); | |||
throw new IllegalArgumentException( message ); | |||
} | |||
else | |||
{ | |||
m_targets.put( name, target ); | |||
} | |||
} | |||
/** | |||
* Add a project reference. | |||
* | |||
* @param name the name of target | |||
* @param project the Project | |||
* @exception IllegalArgumentException if project already exists with same name | |||
*/ | |||
public final void addProject( final String name, final Project project ) | |||
{ | |||
if( null != m_projects.get( name ) ) | |||
{ | |||
final String message = REZ.getString( "duplicate-project.error", name ); | |||
throw new IllegalArgumentException( message ); | |||
} | |||
else | |||
{ | |||
m_projects.put( name, project ); | |||
} | |||
} | |||
} |
@@ -1,553 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.builder; | |||
import java.io.File; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import javax.xml.parsers.SAXParser; | |||
import javax.xml.parsers.SAXParserFactory; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.excalibur.io.FileUtil; | |||
import org.apache.avalon.excalibur.util.StringUtil; | |||
import org.apache.avalon.framework.Version; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.myrmidon.interfaces.builder.ProjectBuilder; | |||
import org.apache.myrmidon.interfaces.builder.ProjectException; | |||
import org.apache.myrmidon.interfaces.model.DefaultNameValidator; | |||
import org.apache.myrmidon.interfaces.model.Dependency; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.model.Target; | |||
import org.apache.myrmidon.interfaces.model.TypeLib; | |||
import org.xml.sax.XMLReader; | |||
/** | |||
* Default implementation to construct project from a build file. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
* | |||
* @ant.type type="project-builder" name="ant2" | |||
*/ | |||
public class DefaultProjectBuilder | |||
extends AbstractLogEnabled | |||
implements ProjectBuilder | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultProjectBuilder.class ); | |||
private static final Version VERSION = new Version( 2, 0, 0 ); | |||
private static final int PROJECT_REFERENCES = 0; | |||
private static final int LIBRARY_IMPORTS = 1; | |||
private static final int IMPLICIT_TASKS = 2; | |||
private static final int TARGETS = 3; | |||
// Use a name validator with the default rules. | |||
private DefaultNameValidator m_nameValidator = new DefaultNameValidator(); | |||
/** | |||
* build a project from file. | |||
* | |||
* @param source the source | |||
* @return the constructed Project | |||
* @exception ProjectException if an error occurs | |||
*/ | |||
public Project build( final String source ) | |||
throws ProjectException | |||
{ | |||
final File file = new File( source ); | |||
return build( file, new HashMap() ); | |||
} | |||
private Project build( final File file, final HashMap projects ) | |||
throws ProjectException | |||
{ | |||
try | |||
{ | |||
// Check for cached project | |||
final String systemID = extractURL( file ); | |||
final Project result = (Project)projects.get( systemID ); | |||
if( null != result ) | |||
{ | |||
return result; | |||
} | |||
// Parse the project file | |||
final Configuration configuration = parseProject( systemID ); | |||
// Build the project model and add to cache | |||
final DefaultProject project = buildProject( file, configuration ); | |||
projects.put( systemID, project ); | |||
// Build using all top-level attributes | |||
buildTopLevelProject( project, configuration, projects ); | |||
return project; | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "ant.project-build.error", | |||
file.getAbsolutePath() ); | |||
throw new ProjectException( message, e ); | |||
} | |||
} | |||
/** | |||
* Builds a project configuration from a build file. | |||
* @param systemID the XML system id of the build file | |||
* @return the project configuration | |||
* @throws ProjectException on parse error | |||
*/ | |||
protected Configuration parseProject( final String systemID ) | |||
throws ProjectException | |||
{ | |||
try | |||
{ | |||
final SAXConfigurationHandler handler = new SAXConfigurationHandler(); | |||
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||
final SAXParser saxParser = saxParserFactory.newSAXParser(); | |||
final XMLReader parser = saxParser.getXMLReader(); | |||
parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false ); | |||
parser.setFeature( "http://xml.org/sax/features/namespaces", false ); | |||
//parser.setFeature( "http://xml.org/sax/features/validation", false ); | |||
parser.setContentHandler( handler ); | |||
parser.setErrorHandler( handler ); | |||
parser.parse( systemID ); | |||
return handler.getConfiguration(); | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "ant.project-parse.error" ); | |||
throw new ProjectException( message, e ); | |||
} | |||
} | |||
/** | |||
* build project from configuration. | |||
* | |||
* @param file the file from which configuration was loaded | |||
* @param configuration the configuration loaded | |||
* @return the created Project | |||
* @exception ProjectException if an error occurs building the project | |||
*/ | |||
private DefaultProject buildProject( final File file, | |||
final Configuration configuration ) | |||
throws ProjectException | |||
{ | |||
if( !configuration.getName().equals( "project" ) ) | |||
{ | |||
final String message = REZ.getString( "ant.no-project-element.error" ); | |||
throw new ProjectException( message ); | |||
} | |||
//get project-level attributes | |||
final String projectName = getProjectName( configuration, file ); | |||
final String baseDirectoryName = configuration.getAttribute( "basedir", null ); | |||
final String defaultTarget = configuration.getAttribute( "default", "main" ); | |||
final Version version = getVersion( configuration ); | |||
if( !VERSION.complies( version ) ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.bad-version.error", VERSION, version ); | |||
throw new ProjectException( message ); | |||
} | |||
//determine base directory for project. Use the directory containing | |||
//the build file as the default. | |||
File baseDirectory = file.getParentFile(); | |||
if( baseDirectoryName != null ) | |||
{ | |||
baseDirectory = FileUtil.resolveFile( baseDirectory, baseDirectoryName ); | |||
} | |||
baseDirectory = baseDirectory.getAbsoluteFile(); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = REZ.getString( "ant.project-banner.notice", | |||
file, baseDirectory ); | |||
getLogger().debug( message ); | |||
} | |||
//create project and ... | |||
final DefaultProject project = new DefaultProject(); | |||
project.setProjectName( projectName ); | |||
project.setDefaultTargetName( defaultTarget ); | |||
project.setBaseDirectory( baseDirectory ); | |||
return project; | |||
} | |||
/** | |||
* Get the project name from the configuration, or create a default name if none | |||
* was supplied. | |||
*/ | |||
private String getProjectName( final Configuration configuration, | |||
final File file ) | |||
throws ProjectException | |||
{ | |||
String projectName = configuration.getAttribute( "name", null ); | |||
if( projectName == null ) | |||
{ | |||
// Create a name based on the file name. | |||
String fileNameBase = FileUtil.removeExtension( file.getName() ); | |||
try | |||
{ | |||
projectName = m_nameValidator.makeValidName( fileNameBase ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
String message = REZ.getString( "ant.project-create-name.error" ); | |||
throw new ProjectException( message, e ); | |||
} | |||
} | |||
else | |||
{ | |||
// Make sure the supplied name is valid. | |||
try | |||
{ | |||
m_nameValidator.validate( projectName ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
String message = REZ.getString( "ant.project-bad-name.error" ); | |||
throw new ProjectException( message, e ); | |||
} | |||
} | |||
return projectName; | |||
} | |||
/** | |||
* Retrieve the version attribute from the specified configuration element. | |||
* Throw exceptions with meaningful errors if malformed or missing. | |||
*/ | |||
private Version getVersion( final Configuration configuration ) | |||
throws ProjectException | |||
{ | |||
try | |||
{ | |||
final String versionString = configuration.getAttribute( "version" ); | |||
return parseVersion( versionString ); | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
final String message = REZ.getString( "ant.version-missing.error" ); | |||
throw new ProjectException( message, ce ); | |||
} | |||
} | |||
/** | |||
* Utility function to extract version | |||
*/ | |||
private Version parseVersion( final String versionString ) | |||
throws ProjectException | |||
{ | |||
try | |||
{ | |||
return Version.getVersion( versionString ); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.malformed.version", versionString ); | |||
throw new ProjectException( message ); | |||
} | |||
} | |||
/** | |||
* Handle all top level elements in configuration. | |||
* | |||
* @param project the project | |||
* @param configuration the Configuration | |||
* @exception ProjectException if an error occurs | |||
*/ | |||
private void buildTopLevelProject( final DefaultProject project, | |||
final Configuration configuration, | |||
final HashMap projects ) | |||
throws ProjectException | |||
{ | |||
final ArrayList implicitTaskList = new ArrayList(); | |||
final Configuration[] children = configuration.getChildren(); | |||
int state = PROJECT_REFERENCES; | |||
for( int i = 0; i < children.length; i++ ) | |||
{ | |||
final Configuration element = children[ i ]; | |||
final String name = element.getName(); | |||
if( PROJECT_REFERENCES == state ) | |||
{ | |||
if( name.equals( "projectref" ) ) | |||
{ | |||
buildProjectRef( project, element, projects ); | |||
continue; | |||
} | |||
else | |||
{ | |||
state = LIBRARY_IMPORTS; | |||
} | |||
} | |||
if( LIBRARY_IMPORTS == state ) | |||
{ | |||
if( name.equals( "import" ) ) | |||
{ | |||
buildTypeLib( project, element ); | |||
continue; | |||
} | |||
else | |||
{ | |||
state = IMPLICIT_TASKS; | |||
} | |||
} | |||
if( IMPLICIT_TASKS == state ) | |||
{ | |||
//Check for any implicit tasks here | |||
if( !name.equals( "target" ) ) | |||
{ | |||
implicitTaskList.add( element ); | |||
continue; | |||
} | |||
else | |||
{ | |||
state = TARGETS; | |||
} | |||
} | |||
if( name.equals( "target" ) ) | |||
{ | |||
buildTarget( project, element ); | |||
} | |||
else | |||
{ | |||
final String message = | |||
REZ.getString( "ant.unknown-toplevel-element.error", name, | |||
element.getLocation() ); | |||
throw new ProjectException( message ); | |||
} | |||
} | |||
final Configuration[] implicitTasks = | |||
(Configuration[])implicitTaskList.toArray( new Configuration[ 0 ] ); | |||
final Target implicitTarget = new Target( implicitTasks, null ); | |||
project.setImplicitTarget( implicitTarget ); | |||
} | |||
private void buildProjectRef( final DefaultProject project, | |||
final Configuration element, | |||
final HashMap projects ) | |||
throws ProjectException | |||
{ | |||
final String name = element.getAttribute( "name", null ); | |||
final String location = element.getAttribute( "location", null ); | |||
if( null == name ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.projectref-no-name.error", | |||
element.getLocation() ); | |||
throw new ProjectException( message ); | |||
} | |||
try | |||
{ | |||
m_nameValidator.validate( name ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.projectref-bad-name.error", | |||
element.getLocation() ); | |||
throw new ProjectException( message, e ); | |||
} | |||
if( null == location ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.projectref-no-location.error", | |||
element.getLocation() ); | |||
throw new ProjectException( message ); | |||
} | |||
// Build the URL of the referenced projects | |||
final File baseDirectory = project.getBaseDirectory(); | |||
final File file = FileUtil.resolveFile( baseDirectory, location ); | |||
// Locate the referenced project, building it if necessary | |||
final Project other = build( file, projects ); | |||
// Add the reference | |||
project.addProject( name, other ); | |||
} | |||
/** | |||
* Validates a project file name, and builds the canonical URL for it. | |||
*/ | |||
private String extractURL( final File file ) throws ProjectException | |||
{ | |||
if( ! file.isFile() ) | |||
{ | |||
final String message = REZ.getString( "ant.no-project-file.error" ); | |||
throw new ProjectException( message ); | |||
} | |||
try | |||
{ | |||
return file.getCanonicalFile().toURL().toString(); | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "ant.project-unexpected.error" ); | |||
throw new ProjectException( message, e ); | |||
} | |||
} | |||
private void buildTypeLib( final DefaultProject project, | |||
final Configuration element ) | |||
throws ProjectException | |||
{ | |||
final String library = element.getAttribute( "library", null ); | |||
final String name = element.getAttribute( "name", null ); | |||
final String type = element.getAttribute( "type", null ); | |||
if( null == library ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.import-no-library.error", element.getLocation() ); | |||
throw new ProjectException( message ); | |||
} | |||
if( null == name || null == type ) | |||
{ | |||
if( null != name || null != type ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.import-malformed.error", element.getLocation() ); | |||
throw new ProjectException( message ); | |||
} | |||
} | |||
project.addTypeLib( new TypeLib( library, type, name ) ); | |||
} | |||
/** | |||
* Build a target from configuration. | |||
* | |||
* @param project the project | |||
* @param target the Configuration | |||
*/ | |||
private void buildTarget( final DefaultProject project, final Configuration target ) | |||
throws ProjectException | |||
{ | |||
final String name = target.getAttribute( "name", null ); | |||
final String depends = target.getAttribute( "depends", null ); | |||
verifyTargetName( name, target ); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = REZ.getString( "ant.target-parse.notice", name ); | |||
getLogger().debug( message ); | |||
} | |||
final Dependency[] dependencies = buildDependsList( depends, target ); | |||
final Target defaultTarget = new Target( target.getChildren(), dependencies ); | |||
//add target to project | |||
project.addTarget( name, defaultTarget ); | |||
} | |||
private void verifyTargetName( final String name, final Configuration target ) | |||
throws ProjectException | |||
{ | |||
if( null == name ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.target-noname.error", target.getLocation() ); | |||
throw new ProjectException( message ); | |||
} | |||
try | |||
{ | |||
m_nameValidator.validate( name ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = | |||
REZ.getString( "ant.target-bad-name.error", target.getLocation() ); | |||
throw new ProjectException( message, e ); | |||
} | |||
} | |||
private Dependency[] buildDependsList( final String depends, | |||
final Configuration target ) | |||
throws ProjectException | |||
{ | |||
//apply depends attribute | |||
if( null == depends ) | |||
{ | |||
return null; | |||
} | |||
final String[] elements = StringUtil.split( depends, "," ); | |||
final ArrayList dependsList = new ArrayList(); | |||
for( int i = 0; i < elements.length; i++ ) | |||
{ | |||
final String dependency = elements[ i ].trim(); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = REZ.getString( "ant.target-dependency.notice", | |||
dependency ); | |||
getLogger().debug( message ); | |||
} | |||
// Split project->target dependencies | |||
final int sep = dependency.indexOf( "->" ); | |||
final String projectName; | |||
final String targetName; | |||
if( sep != -1 ) | |||
{ | |||
projectName = dependency.substring( 0, sep ); | |||
targetName = dependency.substring( sep + 2 ); | |||
} | |||
else | |||
{ | |||
projectName = null; | |||
targetName = dependency; | |||
} | |||
if( targetName.length() == 0 || | |||
( projectName != null && projectName.length() == 0 ) ) | |||
{ | |||
final String message = REZ.getString( "ant.target-bad-dependency.error", | |||
target.getName(), | |||
target.getLocation() ); | |||
throw new ProjectException( message ); | |||
} | |||
dependsList.add( new Dependency( projectName, targetName ) ); | |||
} | |||
return (Dependency[])dependsList.toArray( new Dependency[dependsList.size() ] ); | |||
} | |||
} |
@@ -1,60 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.builder; | |||
import java.util.ArrayList; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
/** | |||
* Handler that reacts to PIs before first element. | |||
* Have to do it this way as there doesn't seem to be a *safe* way | |||
* of redirecting content handlers at runtime while using transformers. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ReactorPIHandler | |||
extends DefaultHandler | |||
{ | |||
private ArrayList m_targets = new ArrayList(); | |||
private ArrayList m_data = new ArrayList(); | |||
public int getPICount() | |||
{ | |||
return m_targets.size(); | |||
} | |||
public String getTarget( final int index ) | |||
{ | |||
return (String)m_targets.get( index ); | |||
} | |||
public String getData( final int index ) | |||
{ | |||
return (String)m_data.get( index ); | |||
} | |||
public void processingInstruction( final String target, final String data ) | |||
throws SAXException | |||
{ | |||
m_targets.add( target ); | |||
m_data.add( data ); | |||
} | |||
public void startElement( final String uri, | |||
final String localName, | |||
final String qName, | |||
final Attributes atts ) | |||
throws SAXException | |||
{ | |||
//Workaround to stop SAX pipeline | |||
throw new StopParsingException(); | |||
} | |||
} |
@@ -1,37 +0,0 @@ | |||
ati.two.stylesheet.pis=Build file can not contain two xsl-stylesheet PIs. | |||
ati.params.error=Malformed PI: expected <?xsl-params location=\"myparams.properties\"?> | |||
ati.param.error=Malformed PI: expected <?xsl-param name=\"foo\" value=\"bar\"?> | |||
ati.style.error=Malformed PI: expected <?xsl-params href=\"mystylesheet.xsl\"?> | |||
ati.loading-params.error=Error loading parameters {0}. Reason: {1}. | |||
ati.loading-style.error=Error locating stylesheet {0}. Reason: {1}. | |||
ati.attribue-expected.error=Expecting an attribute but received {0}. | |||
ati.attribue-unquoted.error=Expecting the value of attribute {0} to be enclosed in quotes. | |||
ant.project-banner.notice=Project {0} base directory: {1}. | |||
ant.target-parse.notice=Parsing target: {0}. | |||
ant.target-dependency.notice=Target dependency: {0} | |||
ant.project-unexpected.error=Unexpected error building project. | |||
ant.project-parse.error=Could not parse project file. | |||
ant.project-build.error=Could not load project from "{0}". | |||
ant.no-project-element.error=Project file must be enclosed in project element. | |||
ant.unknown-toplevel-element.error=Unknown top-level element {0} at {1}. | |||
ant.project-bad-name.error=Invalid project name. | |||
ant.project-create-name.error=Could not create a name for this project. | |||
ant.projectref-no-name.error=Malformed projectref without a name attribute at {0}. | |||
ant.projectref-bad-name.error=Projectref with an invalid name attribute at {0}. | |||
ant.projectref-no-location.error=Malformed projectref without a location attribute at {0}. | |||
ant.import-no-library.error=Malformed import without a library attribute at {0}. | |||
ant.import-malformed.error=Malformed import at {0}. If name or type attribute is specified, both attributes must be specified. | |||
ant.target-noname.error=Discovered un-named target at {0}. | |||
ant.target-bad-name.error=Target with an invalid name at {0}. | |||
ant.target-bad-dependency.error=Discovered empty dependency in target {0} at {1}. | |||
ant.malformed.version=Project has an invalid version "{0}". | |||
ant.version-missing.error=Project has no version attribute. | |||
ant.bad-version.error=Incompatible build file version detected. Expected version {0} but found version {1}. | |||
ant.no-project-file.error=Project file does not exist, or is not a file. | |||
ant.project-convert.notice=Applying compatibility stylesheet to project file. | |||
ant.project-convert.error=Error converting build file. | |||
duplicate-project.error=Can not have two projects referenced in a file with the name {0}. | |||
duplicate-target.error=Can not have two targets in a file with the name {0}. |
@@ -1,25 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.builder; | |||
import org.xml.sax.SAXException; | |||
/** | |||
* Dummy exception to stop parsing "safely". | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class StopParsingException | |||
extends SAXException | |||
{ | |||
public StopParsingException() | |||
{ | |||
super( "" ); | |||
} | |||
} |
@@ -1,97 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.builder; | |||
import java.io.InputStream; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerConfigurationException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||
import org.apache.myrmidon.interfaces.builder.ProjectException; | |||
/** | |||
* A Project Builder which performs an XSL transformation on a project. | |||
* | |||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
* @version $Revision$ $Date$ | |||
* | |||
* @ant.type type="project-builder" name="ant-transform" | |||
*/ | |||
public class TransformingProjectBuilder | |||
extends DefaultProjectBuilder | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( TransformingProjectBuilder.class ); | |||
private static final String STYLESHEET = "ant1convert.xsl"; | |||
private Transformer m_transformer; | |||
/** | |||
* Builds a project Configuration from a project file, applying the | |||
* ant1 conversion stylesheet. | |||
* @param systemID the XML system id for the project file | |||
* @return the project configuration | |||
* @throws ProjectException if a parse error occurs | |||
*/ | |||
protected Configuration parseProject( String systemID ) | |||
throws ProjectException | |||
{ | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = REZ.getString( "ant.project-convert.notice" ); | |||
getLogger().debug( message ); | |||
} | |||
try | |||
{ | |||
// Create a XSLT source for the build file. | |||
Source source = new StreamSource( systemID ); | |||
// Create a configuration handler for the output. | |||
final SAXConfigurationHandler handler = new SAXConfigurationHandler(); | |||
Result result = new SAXResult( handler ); | |||
// Perform the transformation. | |||
getTransformer().transform( source, result ); | |||
return handler.getConfiguration(); | |||
} | |||
catch( Exception e ) | |||
{ | |||
throw new ProjectException( REZ.getString( "ant.project-convert.error" ), | |||
e ); | |||
} | |||
} | |||
/** | |||
* Lazy load a Transformer with the conversion stylesheet. | |||
* @return the initialised Transformer | |||
* @throws TransformerConfigurationException | |||
*/ | |||
private Transformer getTransformer() | |||
throws TransformerConfigurationException | |||
{ | |||
// Lazy loading of stylesheet source. | |||
if( m_transformer == null ) | |||
{ | |||
InputStream stylesheet = | |||
this.getClass().getResourceAsStream( STYLESHEET ); | |||
StreamSource stylesheetSource = new StreamSource( stylesheet ); | |||
TransformerFactory xformFactory = TransformerFactory.newInstance(); | |||
m_transformer = xformFactory.newTransformer( stylesheetSource ); | |||
} | |||
return m_transformer; | |||
} | |||
} |
@@ -1,151 +0,0 @@ | |||
<?xml version="1.0"?> | |||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> | |||
<xsl:output method="xml" indent="yes"/> | |||
<xsl:template match="/project"> | |||
<xsl:comment>Converted Project file.</xsl:comment> | |||
<xsl:copy> | |||
<xsl:attribute name="version">2.0</xsl:attribute> | |||
<xsl:apply-templates select="@*[name() != 'version']" mode="copy"/> | |||
<xsl:apply-templates/> | |||
</xsl:copy> | |||
</xsl:template> | |||
<!-- For projects with a version attribute, simply copy the entire tree. --> | |||
<!-- TODO check for version >= 2.0.0 --> | |||
<xsl:template match="/project[@version]"> | |||
<xsl:comment>Copied Project file.</xsl:comment> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*"/> | |||
<xsl:apply-templates mode="copy"/> | |||
</xsl:copy> | |||
</xsl:template> | |||
<!-- Handle simple target nodes --> | |||
<xsl:template match="/project/target"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*"/> | |||
<xsl:apply-templates/> | |||
</xsl:copy> | |||
</xsl:template> | |||
<!-- Handle target nodes with 'if' --> | |||
<xsl:template match="/project/target[@if]"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*[name() != 'if']"/> | |||
<!-- Put in the if condition --> | |||
<xsl:element name="if"> | |||
<xsl:element name="condition"> | |||
<xsl:element name="is-set"> | |||
<xsl:attribute name="property"> | |||
<xsl:value-of select="@if"/> | |||
</xsl:attribute> | |||
</xsl:element> | |||
</xsl:element> | |||
<!-- Now add the target content --> | |||
<xsl:apply-templates/> | |||
</xsl:element> | |||
</xsl:copy> | |||
</xsl:template> | |||
<!-- Handle target nodes with 'unless' --> | |||
<xsl:template match="/project/target[@unless]"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*[name() != 'unless']"/> | |||
<!-- Put in the unless condition --> | |||
<xsl:element name="if"> | |||
<xsl:element name="condition"> | |||
<xsl:element name="not"> | |||
<xsl:element name="is-set"> | |||
<xsl:attribute name="property"> | |||
<xsl:value-of select="@unless"/> | |||
</xsl:attribute> | |||
</xsl:element> | |||
</xsl:element> | |||
</xsl:element> | |||
<!-- Now add the target content --> | |||
<xsl:apply-templates/> | |||
</xsl:element> | |||
</xsl:copy> | |||
</xsl:template> | |||
<!-- Handle target nodes with 'if' and 'unless' --> | |||
<xsl:template match="/project/target[@if and @unless]"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*[name()!='if' and name()!='unless']"/> | |||
<!-- Put in the 'if' condition --> | |||
<xsl:element name="if"> | |||
<xsl:element name="condition"> | |||
<xsl:element name="is-set"> | |||
<xsl:attribute name="property"> | |||
<xsl:value-of select="@if"/> | |||
</xsl:attribute> | |||
</xsl:element> | |||
</xsl:element> | |||
<!-- Put in the 'unless' condition --> | |||
<xsl:element name="if"> | |||
<xsl:element name="condition"> | |||
<xsl:element name="not"> | |||
<xsl:element name="is-set"> | |||
<xsl:attribute name="property"> | |||
<xsl:value-of select="@unless"/> | |||
</xsl:attribute> | |||
</xsl:element> | |||
</xsl:element> | |||
</xsl:element> | |||
<!-- Now add the target content --> | |||
<xsl:apply-templates/> | |||
</xsl:element> | |||
</xsl:element> | |||
</xsl:copy> | |||
</xsl:template> | |||
<!-- Handle task nodes, prepending "ant1." --> | |||
<xsl:template match="*"> | |||
<xsl:element name="ant1.{name()}"> | |||
<xsl:apply-templates select="@*"/> | |||
<xsl:apply-templates mode="copy"/> | |||
</xsl:element> | |||
</xsl:template> | |||
<!-- Copy all elements in copy-mode --> | |||
<xsl:template match="*" mode="copy"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*"/> | |||
<xsl:apply-templates mode="copy"/> | |||
</xsl:copy> | |||
</xsl:template> | |||
<!-- Always copy attributes --> | |||
<xsl:template match="@*"> | |||
<xsl:copy/> | |||
</xsl:template> | |||
<xsl:template match="@*" mode="copy"> | |||
<xsl:copy/> | |||
</xsl:template> | |||
<!-- Always copy comments --> | |||
<xsl:template match="comment()"> | |||
<xsl:copy/> | |||
</xsl:template> | |||
<xsl:template match="comment()" mode="copy"> | |||
<xsl:copy/> | |||
</xsl:template> | |||
</xsl:stylesheet> | |||
@@ -1,305 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.classloader; | |||
import java.io.File; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.jar.JarFile; | |||
import java.util.jar.Manifest; | |||
import org.apache.aut.nativelib.PathUtil; | |||
import org.apache.avalon.excalibur.extension.Extension; | |||
import org.apache.avalon.excalibur.extension.OptionalPackage; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.context.Context; | |||
import org.apache.avalon.framework.context.ContextException; | |||
import org.apache.avalon.framework.context.Contextualizable; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.interfaces.classloader.ClassLoaderException; | |||
import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||
/** | |||
* A default implementation of a ClassLoader manager. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultClassLoaderManager | |||
extends AbstractLogEnabled | |||
implements ClassLoaderManager, Serviceable, Contextualizable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultClassLoaderManager.class ); | |||
/** | |||
* Map from File/ArrayList to the ClassLoader for that file/files. | |||
*/ | |||
private final Map m_classLoaders = new HashMap(); | |||
private ExtensionManager m_extensionManager; | |||
private ClassLoader m_commonClassLoader; | |||
public DefaultClassLoaderManager() | |||
{ | |||
} | |||
public DefaultClassLoaderManager( final ClassLoader commonClassLoader ) | |||
{ | |||
m_commonClassLoader = commonClassLoader; | |||
} | |||
public void contextualize( final Context context ) throws ContextException | |||
{ | |||
if( null == m_commonClassLoader ) | |||
{ | |||
m_commonClassLoader = (ClassLoader)context.get( "myrmidon.shared.classloader" ); | |||
} | |||
} | |||
/** | |||
* Retrieve relevent services needed to deploy. | |||
*/ | |||
public void service( final ServiceManager serviceManager ) | |||
throws ServiceException | |||
{ | |||
m_extensionManager = (ExtensionManager)serviceManager.lookup( ExtensionManager.ROLE ); | |||
} | |||
/** | |||
* Returns the common ClassLoader. This is the parent of all classloaders | |||
* built by this ClassLoaderManager. | |||
*/ | |||
public ClassLoader getCommonClassLoader() | |||
{ | |||
return m_commonClassLoader; | |||
} | |||
/** | |||
* Creates a class loader for a Jar file. | |||
*/ | |||
public ClassLoader getClassLoader( final File file ) throws ClassLoaderException | |||
{ | |||
try | |||
{ | |||
final File canonFile = file.getCanonicalFile(); | |||
// Check for cached classloader, creating it if required | |||
ClassLoader loader = (ClassLoader)m_classLoaders.get( canonFile ); | |||
if( loader == null ) | |||
{ | |||
checkFile( canonFile ); | |||
final OptionalPackage optionalPackage = toOptionalPackage( canonFile ); | |||
loader = buildClassLoader( optionalPackage, new HashSet() ); | |||
} | |||
return loader; | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "create-classloader-for-file.error", file ); | |||
throw new ClassLoaderException( message, e ); | |||
} | |||
} | |||
/** | |||
* Creates a class loader for a set of Jar files. | |||
*/ | |||
public ClassLoader createClassLoader( final File[] files ) throws ClassLoaderException | |||
{ | |||
try | |||
{ | |||
if( files == null || files.length == 0 ) | |||
{ | |||
return m_commonClassLoader; | |||
} | |||
// Build a list of optional packages for the files | |||
final OptionalPackage[] packages = new OptionalPackage[ files.length ]; | |||
for( int i = 0; i < files.length; i++ ) | |||
{ | |||
final File canonFile = files[ i ].getCanonicalFile(); | |||
checkFile( canonFile ); | |||
packages[ i ] = toOptionalPackage( canonFile ); | |||
} | |||
// Build the classloaders for the required extensions | |||
final ClassLoader[] parentClassLoaders = buildParentClassLoaders( packages, new HashSet() ); | |||
// Build the classloader | |||
final URL[] urls = buildClasspath( files ); | |||
return new MultiParentURLClassLoader( urls, parentClassLoaders ); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String fileNames = PathUtil.formatPath( files ); | |||
final String message = REZ.getString( "create-classloader-for-files.error", fileNames ); | |||
throw new ClassLoaderException( message, e ); | |||
} | |||
} | |||
/** | |||
* Builds the classloader for an optional package. | |||
*/ | |||
private ClassLoader buildClassLoader( final OptionalPackage pkg, | |||
final Set pending ) | |||
throws Exception | |||
{ | |||
final File jarFile = pkg.getFile(); | |||
// Check for cached classloader | |||
ClassLoader classLoader = (ClassLoader)m_classLoaders.get( jarFile ); | |||
if( classLoader != null ) | |||
{ | |||
return classLoader; | |||
} | |||
// Check for cyclic dependency | |||
if( pending.contains( jarFile ) ) | |||
{ | |||
final String message = REZ.getString( "dependency-cycle.error", jarFile ); | |||
throw new Exception( message ); | |||
} | |||
pending.add( jarFile ); | |||
// Build the classloaders for the extensions required by this optional | |||
// package | |||
final ClassLoader[] parentClassLoaders = | |||
buildParentClassLoaders( new OptionalPackage[] { pkg }, pending ); | |||
// Create and cache the classloader | |||
final URL[] urls = { jarFile.toURL() }; | |||
classLoader = new MultiParentURLClassLoader( urls, parentClassLoaders ); | |||
m_classLoaders.put( jarFile, classLoader ); | |||
pending.remove( jarFile ); | |||
return classLoader; | |||
} | |||
/** | |||
* Builds the parent classloaders for a set of optional packages. That is, | |||
* the classloaders for all of the extensions required by the given set | |||
* of optional packages. | |||
*/ | |||
private ClassLoader[] buildParentClassLoaders( final OptionalPackage[] packages, | |||
final Set pending ) | |||
throws Exception | |||
{ | |||
final ArrayList classLoaders = new ArrayList(); | |||
// Include the common class loader | |||
classLoaders.add( m_commonClassLoader ); | |||
// Build the classloader for each optional package, filtering out duplicates | |||
for( int i = 0; i < packages.length; i++ ) | |||
{ | |||
final OptionalPackage optionalPackage = packages[ i ]; | |||
// Locate the dependencies for this jar file | |||
final OptionalPackage[] requiredPackages = getOptionalPackagesFor( optionalPackage ); | |||
// Build the classloader for the package | |||
for( int j = 0; j < requiredPackages.length; j++ ) | |||
{ | |||
final OptionalPackage requiredPackage = requiredPackages[j ]; | |||
final ClassLoader classLoader = buildClassLoader( requiredPackage, pending ); | |||
if( ! classLoaders.contains( classLoader ) ) | |||
{ | |||
classLoaders.add( classLoader ); | |||
} | |||
} | |||
} | |||
return (ClassLoader[])classLoaders.toArray( new ClassLoader[classLoaders.size() ] ); | |||
} | |||
/** | |||
* Assembles a set of files into a URL classpath. | |||
*/ | |||
private URL[] buildClasspath( final File[] files ) | |||
throws MalformedURLException | |||
{ | |||
final URL[] urls = new URL[ files.length ]; | |||
for( int i = 0; i < files.length; i++ ) | |||
{ | |||
urls[ i ] = files[i ].toURL(); | |||
} | |||
return urls; | |||
} | |||
/** | |||
* Builds an OptionalPackage for a Jar file. | |||
* | |||
* @param file the jar. | |||
*/ | |||
private OptionalPackage toOptionalPackage( final File file ) | |||
throws Exception | |||
{ | |||
// Determine the extensions required by this file | |||
final JarFile jarFile = new JarFile( file ); | |||
final Manifest manifest = jarFile.getManifest(); | |||
final Extension[] required = Extension.getRequired( manifest ); | |||
return new OptionalPackage( file, new Extension[0], required ); | |||
} | |||
/** | |||
* Locates the optional packages required by an optional package. | |||
*/ | |||
private OptionalPackage[] getOptionalPackagesFor( final OptionalPackage pkg ) | |||
throws Exception | |||
{ | |||
// Locate the optional packages that provide the required extesions | |||
final Extension[] required = pkg.getRequiredExtensions(); | |||
final ArrayList packages = new ArrayList(); | |||
for( int i = 0; i < required.length; i++ ) | |||
{ | |||
final Extension extension = required[i ]; | |||
final OptionalPackage optionalPackage = m_extensionManager.getOptionalPackage( extension ); | |||
if( optionalPackage == null ) | |||
{ | |||
final String message = | |||
REZ.getString( "unsatisfied.extension.error", | |||
pkg.getFile(), | |||
extension.getExtensionName(), | |||
extension.getSpecificationVersion() ); | |||
throw new Exception( message ); | |||
} | |||
packages.add( optionalPackage ); | |||
} | |||
return (OptionalPackage[])packages.toArray( new OptionalPackage[packages.size() ] ); | |||
} | |||
/** | |||
* Ensures a file exists and is not a directory. | |||
*/ | |||
private void checkFile( final File file ) | |||
throws DeploymentException | |||
{ | |||
if( !file.exists() ) | |||
{ | |||
final String message = REZ.getString( "no-file.error", file ); | |||
throw new DeploymentException( message ); | |||
} | |||
if( file.isDirectory() ) | |||
{ | |||
final String message = REZ.getString( "file-is-dir.error", file ); | |||
throw new DeploymentException( message ); | |||
} | |||
} | |||
} |
@@ -1,141 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.classloader; | |||
import java.io.IOException; | |||
import java.net.URL; | |||
import java.net.URLClassLoader; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.Enumeration; | |||
import java.util.List; | |||
import java.util.Set; | |||
import java.util.HashSet; | |||
/** | |||
* A URLClassLoader with more than one parent. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class MultiParentURLClassLoader | |||
extends URLClassLoader | |||
{ | |||
private final ClassLoader[] m_parents; | |||
/** | |||
* Constructs a new URLClassLoader for the given URLs. | |||
* | |||
* @param urls the URLs from which to load classes and resources | |||
* @param parents the parent class loaderer for delegation | |||
*/ | |||
public MultiParentURLClassLoader( final URL[] urls, final ClassLoader[] parents ) | |||
{ | |||
super( urls ); | |||
m_parents = parents; | |||
} | |||
/** | |||
* Finds a class. | |||
* | |||
* @param name the name of the class | |||
* @return the resulting class | |||
* @exception ClassNotFoundException if the class could not be found | |||
*/ | |||
protected Class findClass( final String name ) | |||
throws ClassNotFoundException | |||
{ | |||
// Try the parent classloaders first | |||
for( int i = 0; i < m_parents.length; i++ ) | |||
{ | |||
try | |||
{ | |||
final ClassLoader parent = m_parents[ i ]; | |||
return parent.loadClass( name ); | |||
} | |||
catch( ClassNotFoundException e ) | |||
{ | |||
// Ignore - continue to the next ClassLoader | |||
} | |||
} | |||
// Now this classloader | |||
return super.findClass( name ); | |||
} | |||
/** | |||
* Finds a resource. | |||
* | |||
* @param name the name of the resource | |||
* @return a <code>URL</code> for the resource, or <code>null</code> | |||
* if the resource could not be found. | |||
*/ | |||
public URL findResource( final String name ) | |||
{ | |||
// Try the parent classloaders first | |||
for( int i = 0; i < m_parents.length; i++ ) | |||
{ | |||
final ClassLoader parent = m_parents[ i ]; | |||
final URL resource = parent.getResource( name ); | |||
if( resource != null ) | |||
{ | |||
return resource; | |||
} | |||
} | |||
// Now this classloader | |||
return super.findResource( name ); | |||
} | |||
/** | |||
* Returns an Enumeration of URLs representing all of the resources | |||
* having the specified name. | |||
* | |||
* @param name the resource name | |||
* @throws IOException if an I/O exception occurs | |||
* @return an <code>Enumeration</code> of <code>URL</code>s | |||
*/ | |||
public Enumeration findResources( final String name ) throws IOException | |||
{ | |||
// Need to filter out duplicate resources | |||
final ArrayList urls = new ArrayList(); | |||
final Set urlSet = new HashSet(); | |||
// Gather the resources from the parent classloaders | |||
for( int i = 0; i < m_parents.length; i++ ) | |||
{ | |||
final ClassLoader parent = m_parents[ i ]; | |||
final Enumeration enum = parent.getResources( name ); | |||
addUrls( enum, urls, urlSet ); | |||
} | |||
// Gather the resources from this classloader | |||
addUrls( super.findResources( name ), urls, urlSet ); | |||
return Collections.enumeration( urls ); | |||
} | |||
/** | |||
* Adds those URLs not already present. | |||
*/ | |||
private void addUrls( final Enumeration enum, | |||
final List urls, | |||
final Set urlSet ) | |||
{ | |||
while( enum.hasMoreElements() ) | |||
{ | |||
final URL url = (URL)enum.nextElement(); | |||
final String urlStr = url.toExternalForm(); | |||
if( !urlSet.contains( urlStr ) ) | |||
{ | |||
urls.add( url ); | |||
urlSet.add( urlStr ); | |||
} | |||
} | |||
} | |||
} |
@@ -1,5 +0,0 @@ | |||
create-classloader-for-file.error=Could not create a ClassLoader for "{0}". | |||
create-classloader-for-files.error=Could not create a ClassLoader for {0}. | |||
unsatisfied.extension.error=Library "{0}" requires unknown extension "{1}" ( version {2}). | |||
no-file.error=Could not find library "{0}". | |||
file-is-dir.error=Library "{0}" is a directory. |
@@ -1,567 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Method; | |||
import java.util.ArrayList; | |||
import org.apache.aut.converter.Converter; | |||
import org.apache.aut.converter.ConverterException; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.Configurable; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.logger.LogEnabled; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
/** | |||
* Class used to configure tasks. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @ant.type type="configurer" name="classic" | |||
*/ | |||
public class ClassicConfigurer | |||
extends AbstractLogEnabled | |||
implements Configurer, Serviceable, LogEnabled | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultConfigurer.class ); | |||
///Compile time constant to turn on extreme debugging | |||
private static final boolean DEBUG = false; | |||
///Converter to use for converting between values | |||
private Converter m_converter; | |||
public void service( final ServiceManager serviceManager ) | |||
throws ServiceException | |||
{ | |||
m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||
} | |||
/** | |||
* Configure an object based on a configuration in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* The implementation of this method should only use the methods | |||
* specified by the supplied class. It is an error for the specified | |||
* class not to be a base class or interface compatible with specified | |||
* object. | |||
* | |||
* @param object the object | |||
* @param clazz the Class object to use during configuration | |||
* @param configuration the configuration | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
public void configureElement( Object object, | |||
Class clazz, | |||
Configuration configuration, | |||
TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
throw new UnsupportedOperationException(); | |||
} | |||
/** | |||
* Configure named attribute of object in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* The implementation of this method should only use the methods | |||
* specified by the supplied class. It is an error for the specified | |||
* class not to be a base class or interface compatible with specified | |||
* object. | |||
* | |||
* @param object the object | |||
* @param clazz the Class object to use during configuration | |||
* @param name the attribute name | |||
* @param value the attribute value | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
public void configureAttribute( Object object, | |||
Class clazz, | |||
String name, | |||
String value, | |||
TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
throw new UnsupportedOperationException(); | |||
} | |||
/** | |||
* Configure a task based on a configuration in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* This one does it by first checking if object implements Configurable | |||
* and if it does will pass the task the configuration - else it will use | |||
* mapping rules to map configuration to types | |||
* | |||
* @param object the object | |||
* @param configuration the configuration | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
public void configureElement( final Object object, | |||
final Configuration configuration, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
if( DEBUG ) | |||
{ | |||
final String message = REZ.getString( "configuring-object.notice", object ); | |||
getLogger().debug( message ); | |||
} | |||
if( object instanceof Configurable ) | |||
{ | |||
if( DEBUG ) | |||
{ | |||
final String message = REZ.getString( "configurable.notice" ); | |||
getLogger().debug( message ); | |||
} | |||
final Configurable configurable = (Configurable)object; | |||
configurable.configure( configuration ); | |||
} | |||
else | |||
{ | |||
if( DEBUG ) | |||
{ | |||
final String message = REZ.getString( "reflection.notice" ); | |||
getLogger().debug( message ); | |||
} | |||
final String[] attributes = configuration.getAttributeNames(); | |||
for( int i = 0; i < attributes.length; i++ ) | |||
{ | |||
final String name = attributes[ i ]; | |||
final String value = configuration.getAttribute( name ); | |||
if( DEBUG ) | |||
{ | |||
final String message = REZ.getString( "configure-attribute.notice", | |||
name, value ); | |||
getLogger().debug( message ); | |||
} | |||
doConfigureAttribute( object, name, value, context ); | |||
} | |||
final Configuration[] children = configuration.getChildren(); | |||
for( int i = 0; i < children.length; i++ ) | |||
{ | |||
final Configuration child = children[ i ]; | |||
if( DEBUG ) | |||
{ | |||
final String message = | |||
REZ.getString( "configure-subelement.notice", child.getName() ); | |||
getLogger().debug( message ); | |||
} | |||
doConfigureElement( object, child, context ); | |||
} | |||
final String content = configuration.getValue( null ); | |||
if( null != content ) | |||
{ | |||
if( !content.trim().equals( "" ) ) | |||
{ | |||
if( DEBUG ) | |||
{ | |||
final String message = | |||
REZ.getString( "configure-content.notice", content ); | |||
getLogger().debug( message ); | |||
} | |||
configureContent( object, content, context ); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Configure named attribute of object in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* @param object the object | |||
* @param name the attribute name | |||
* @param value the attribute value | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
public void configureAttribute( final Object object, | |||
final String name, | |||
final String value, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
doConfigureAttribute( object, name, value, context ); | |||
} | |||
/** | |||
* Try to configure content of an object. | |||
* | |||
* @param object the object | |||
* @param content the content value to be set | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
private void configureContent( final Object object, | |||
final String content, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
setValue( object, "addContent", content, context ); | |||
} | |||
private void doConfigureAttribute( final Object object, | |||
final String name, | |||
final String value, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
final String methodName = getMethodNameFor( name ); | |||
setValue( object, methodName, value, context ); | |||
} | |||
private void setValue( final Object object, | |||
final String methodName, | |||
final String value, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
// OMFG the rest of this is soooooooooooooooooooooooooooooooo | |||
// slow. Need to cache results per class etc. | |||
final Class clazz = object.getClass(); | |||
final Method[] methods = getMethodsFor( clazz, methodName ); | |||
if( 0 == methods.length ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-attribute-method.error", methodName ); | |||
throw new ConfigurationException( message ); | |||
} | |||
setValue( object, value, context, methods ); | |||
} | |||
private void setValue( final Object object, | |||
final String value, | |||
final TaskContext context, | |||
final Method[] methods ) | |||
throws ConfigurationException | |||
{ | |||
try | |||
{ | |||
final Object objectValue = context.resolveValue( value ); | |||
setValue( object, objectValue, methods, context ); | |||
} | |||
catch( final TaskException te ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-property-resolve.error", value ); | |||
throw new ConfigurationException( message, te ); | |||
} | |||
} | |||
private void setValue( final Object object, | |||
Object value, | |||
final Method[] methods, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
final Class sourceClass = value.getClass(); | |||
final String source = sourceClass.getName(); | |||
for( int i = 0; i < methods.length; i++ ) | |||
{ | |||
if( setValue( object, value, methods[ i ], context ) ) | |||
{ | |||
return; | |||
} | |||
} | |||
final String message = | |||
REZ.getString( "no-can-convert.error", methods[ 0 ].getName(), source ); | |||
throw new ConfigurationException( message ); | |||
} | |||
private boolean setValue( final Object object, | |||
final Object originalValue, | |||
final Method method, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
Class parameterType = method.getParameterTypes()[ 0 ]; | |||
if( parameterType.isPrimitive() ) | |||
{ | |||
parameterType = getComplexTypeFor( parameterType ); | |||
} | |||
Object value = originalValue; | |||
try | |||
{ | |||
value = m_converter.convert( parameterType, value, context ); | |||
} | |||
catch( final ConverterException ce ) | |||
{ | |||
if( DEBUG ) | |||
{ | |||
final String message = REZ.getString( "no-converter.error" ); | |||
getLogger().debug( message, ce ); | |||
} | |||
throw new ConfigurationException( ce.getMessage(), ce ); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-convert-for-attribute.error", method.getName() ); | |||
throw new ConfigurationException( message, e ); | |||
} | |||
if( null == value ) | |||
{ | |||
return false; | |||
} | |||
try | |||
{ | |||
method.invoke( object, new Object[]{value} ); | |||
} | |||
catch( final IllegalAccessException iae ) | |||
{ | |||
//should never happen .... | |||
final String message = REZ.getString( "illegal-access.error" ); | |||
throw new ConfigurationException( message, iae ); | |||
} | |||
catch( final InvocationTargetException ite ) | |||
{ | |||
final String message = REZ.getString( "invoke-target.error", method.getName() ); | |||
throw new ConfigurationException( message, ite ); | |||
} | |||
return true; | |||
} | |||
private Class getComplexTypeFor( final Class clazz ) | |||
{ | |||
if( String.class == clazz ) | |||
{ | |||
return String.class; | |||
} | |||
else if( Integer.TYPE.equals( clazz ) ) | |||
{ | |||
return Integer.class; | |||
} | |||
else if( Long.TYPE.equals( clazz ) ) | |||
{ | |||
return Long.class; | |||
} | |||
else if( Short.TYPE.equals( clazz ) ) | |||
{ | |||
return Short.class; | |||
} | |||
else if( Byte.TYPE.equals( clazz ) ) | |||
{ | |||
return Byte.class; | |||
} | |||
else if( Boolean.TYPE.equals( clazz ) ) | |||
{ | |||
return Boolean.class; | |||
} | |||
else if( Float.TYPE.equals( clazz ) ) | |||
{ | |||
return Float.class; | |||
} | |||
else if( Double.TYPE.equals( clazz ) ) | |||
{ | |||
return Double.class; | |||
} | |||
else | |||
{ | |||
final String message = REZ.getString( "no-complex-type.error", clazz.getName() ); | |||
throw new IllegalArgumentException( message ); | |||
} | |||
} | |||
private Method[] getMethodsFor( final Class clazz, final String methodName ) | |||
{ | |||
final Method[] methods = clazz.getMethods(); | |||
final ArrayList matches = new ArrayList(); | |||
for( int i = 0; i < methods.length; i++ ) | |||
{ | |||
final Method method = methods[ i ]; | |||
if( methodName.equals( method.getName() ) && | |||
Method.PUBLIC == ( method.getModifiers() & Method.PUBLIC ) ) | |||
{ | |||
if( method.getReturnType().equals( Void.TYPE ) ) | |||
{ | |||
final Class[] parameters = method.getParameterTypes(); | |||
if( 1 == parameters.length ) | |||
{ | |||
matches.add( method ); | |||
} | |||
} | |||
} | |||
} | |||
return (Method[])matches.toArray( new Method[ 0 ] ); | |||
} | |||
private Method[] getCreateMethodsFor( final Class clazz, final String methodName ) | |||
{ | |||
final Method[] methods = clazz.getMethods(); | |||
final ArrayList matches = new ArrayList(); | |||
for( int i = 0; i < methods.length; i++ ) | |||
{ | |||
final Method method = methods[ i ]; | |||
if( methodName.equals( method.getName() ) && | |||
Method.PUBLIC == ( method.getModifiers() & Method.PUBLIC ) ) | |||
{ | |||
final Class returnType = method.getReturnType(); | |||
if( !returnType.equals( Void.TYPE ) && | |||
!returnType.isPrimitive() ) | |||
{ | |||
final Class[] parameters = method.getParameterTypes(); | |||
if( 0 == parameters.length ) | |||
{ | |||
matches.add( method ); | |||
} | |||
} | |||
} | |||
} | |||
return (Method[])matches.toArray( new Method[ 0 ] ); | |||
} | |||
private String getMethodNameFor( final String attribute ) | |||
{ | |||
return "set" + getJavaNameFor( attribute.toLowerCase() ); | |||
} | |||
private String getJavaNameFor( final String name ) | |||
{ | |||
final StringBuffer sb = new StringBuffer(); | |||
int index = name.indexOf( '-' ); | |||
int last = 0; | |||
while( -1 != index ) | |||
{ | |||
final String word = name.substring( last, index ).toLowerCase(); | |||
sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); | |||
sb.append( word.substring( 1, word.length() ) ); | |||
last = index + 1; | |||
index = name.indexOf( '-', last ); | |||
} | |||
index = name.length(); | |||
final String word = name.substring( last, index ).toLowerCase(); | |||
sb.append( Character.toUpperCase( word.charAt( 0 ) ) ); | |||
sb.append( word.substring( 1, word.length() ) ); | |||
return sb.toString(); | |||
} | |||
private void doConfigureElement( final Object object, | |||
final Configuration configuration, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
final String name = configuration.getName(); | |||
final String javaName = getJavaNameFor( name ); | |||
// OMFG the rest of this is soooooooooooooooooooooooooooooooo | |||
// slow. Need to cache results per class etc. | |||
final Class clazz = object.getClass(); | |||
Method[] methods = getMethodsFor( clazz, "add" + javaName ); | |||
if( 0 != methods.length ) | |||
{ | |||
//guess it is first method ???? | |||
addElement( object, methods[ 0 ], configuration, context ); | |||
} | |||
else | |||
{ | |||
methods = getCreateMethodsFor( clazz, "create" + javaName ); | |||
if( 0 == methods.length ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-element-method.error", javaName ); | |||
throw new ConfigurationException( message ); | |||
} | |||
//guess it is first method ???? | |||
createElement( object, methods[ 0 ], configuration, context ); | |||
} | |||
} | |||
private void createElement( final Object object, | |||
final Method method, | |||
final Configuration configuration, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
try | |||
{ | |||
final Object created = method.invoke( object, new Object[ 0 ] ); | |||
doConfigureElement( created, configuration, context ); | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
throw ce; | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "subelement-create.error" ); | |||
throw new ConfigurationException( message, e ); | |||
} | |||
} | |||
private void addElement( final Object object, | |||
final Method method, | |||
final Configuration configuration, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
try | |||
{ | |||
final Class clazz = method.getParameterTypes()[ 0 ]; | |||
final Object created = clazz.newInstance(); | |||
doConfigureElement( created, configuration, context ); | |||
method.invoke( object, new Object[]{created} ); | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
throw ce; | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "subelement-create.error" ); | |||
throw new ConfigurationException( message, e ); | |||
} | |||
} | |||
} |
@@ -1,57 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
/** | |||
* A default configuration state implementation. Keeps track of which | |||
* of the object's properties have been set. | |||
* | |||
* @author Adam Murdoch | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class ConfigurationState | |||
{ | |||
private final int[] m_propertyCount; | |||
private final ObjectConfigurer m_configurer; | |||
private final Object m_object; | |||
public ConfigurationState( final ObjectConfigurer configurer, | |||
final Object object, | |||
final int propertyCount ) | |||
{ | |||
m_configurer = configurer; | |||
m_object = object; | |||
m_propertyCount = new int[ propertyCount ]; | |||
} | |||
/** | |||
* Returns the configurer being used to configure the object. | |||
*/ | |||
public ObjectConfigurer getConfigurer() | |||
{ | |||
return m_configurer; | |||
} | |||
/** Returns the object being configured. */ | |||
public Object getObject() | |||
{ | |||
return m_object; | |||
} | |||
/** Returns a property count. */ | |||
public int getPropertyCount( final int index ) | |||
{ | |||
return m_propertyCount[ index ]; | |||
} | |||
/** Increments a property count. */ | |||
public void incPropertyCount( final int index ) | |||
{ | |||
m_propertyCount[ index ]++; | |||
} | |||
} |
@@ -1,645 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.aut.converter.Converter; | |||
import org.apache.aut.converter.ConverterException; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.Configurable; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.logger.LogEnabled; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.framework.DataType; | |||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* Class used to configure tasks. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
* @ant.type type="configurer" name="default" | |||
*/ | |||
public class DefaultConfigurer | |||
extends AbstractLogEnabled | |||
implements Configurer, Serviceable, LogEnabled | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultConfigurer.class ); | |||
///Converter to use for converting between values | |||
private Converter m_converter; | |||
//TypeManager to use to create types in typed adders | |||
private TypeManager m_typeManager; | |||
//RoleManager to use to map from type names -> role shorthand | |||
private RoleManager m_roleManager; | |||
///Cached object configurers. This is a map from Class to the | |||
///ObjectConfigurer for that class. | |||
private Map m_configurerCache = new HashMap(); | |||
public void service( final ServiceManager serviceManager ) | |||
throws ServiceException | |||
{ | |||
m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||
m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||
m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||
} | |||
/** | |||
* Configure a task based on a configuration in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* This one does it by first checking if object implements Configurable | |||
* and if it does will pass the task the configuration - else it will use | |||
* mapping rules to map configuration to types | |||
* | |||
* @param object the object | |||
* @param configuration the configuration | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
public void configureElement( final Object object, | |||
final Configuration configuration, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
configureElement( object, object.getClass(), configuration, context ); | |||
} | |||
public void configureElement( final Object object, | |||
final Class clazz, | |||
final Configuration configuration, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
try | |||
{ | |||
// Configure the object | |||
configureObject( object, clazz, configuration, context ); | |||
} | |||
catch( final ReportableConfigurationException e ) | |||
{ | |||
// Already have a reasonable error message - so rethrow | |||
throw e.getCause(); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
// Wrap all other errors with general purpose error message | |||
final String message = REZ.getString( "bad-configure-element.error", | |||
configuration.getName() ); | |||
throw new ConfigurationException( message, e ); | |||
} | |||
} | |||
/** | |||
* Does the work of configuring an object. | |||
* | |||
* @throws ReportableConfigurationException On error. This exception | |||
* indicates that the error has been wrapped with an appropriate | |||
* error message. | |||
* @throws Exception On error | |||
*/ | |||
private void configureObject( final Object object, | |||
final Class clazz, | |||
final Configuration configuration, | |||
final TaskContext context ) | |||
throws Exception | |||
{ | |||
if( object instanceof Configurable ) | |||
{ | |||
// Let the object configure itself | |||
( (Configurable)object ).configure( configuration ); | |||
} | |||
else | |||
{ | |||
// Start configuration of the object | |||
final String elemName = configuration.getName(); | |||
final ObjectConfigurer configurer = getConfigurer( clazz ); | |||
final ConfigurationState state = configurer.startConfiguration( object ); | |||
// Set each of the attributes | |||
final String[] attributes = configuration.getAttributeNames(); | |||
for( int i = 0; i < attributes.length; i++ ) | |||
{ | |||
final String name = attributes[ i ]; | |||
try | |||
{ | |||
// Set the attribute | |||
final String value = configuration.getAttribute( name ); | |||
setAttribute( state, name, value, context ); | |||
} | |||
catch( final NoSuchPropertyException nspe ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-such-attribute.error", elemName, name ); | |||
throw new ReportableConfigurationException( message ); | |||
} | |||
catch( final Exception ce ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-set-attribute.error", elemName, name ); | |||
throw new ReportableConfigurationException( message, ce ); | |||
} | |||
} | |||
// Set the text content | |||
final String content = configuration.getValue( null ); | |||
if( null != content && content.length() > 0 ) | |||
{ | |||
try | |||
{ | |||
// Set the content | |||
setContent( state, content, context ); | |||
} | |||
catch( final NoSuchPropertyException nspe ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-content.error", elemName ); | |||
throw new ReportableConfigurationException( message ); | |||
} | |||
catch( final Exception ce ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-set-content.error", elemName ); | |||
throw new ReportableConfigurationException( message, ce ); | |||
} | |||
} | |||
// Create and configure each of the child elements | |||
final Configuration[] children = configuration.getChildren(); | |||
for( int i = 0; i < children.length; i++ ) | |||
{ | |||
final Configuration childConfig = children[ i ]; | |||
final String name = childConfig.getName(); | |||
try | |||
{ | |||
configureElement( state, childConfig, context ); | |||
} | |||
catch( final NoSuchPropertyException nspe ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-such-element.error", elemName, name ); | |||
throw new ReportableConfigurationException( message ); | |||
} | |||
catch( final ReportableConfigurationException ce ) | |||
{ | |||
throw ce; | |||
} | |||
catch( final Exception ce ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-configure-element.error", name ); | |||
throw new ReportableConfigurationException( message, ce ); | |||
} | |||
} | |||
// Finish configuring the object | |||
configurer.finishConfiguration( state ); | |||
} | |||
} | |||
/** | |||
* Configure named attribute of object in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* @param object the object | |||
* @param name the attribute name | |||
* @param value the attribute value | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
public void configureAttribute( final Object object, | |||
final String name, | |||
final String value, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
configureAttribute( object, object.getClass(), name, value, context ); | |||
} | |||
/** | |||
* Configure named attribute of object in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* @param object the object | |||
* @param name the attribute name | |||
* @param value the attribute value | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
public void configureAttribute( final Object object, | |||
final Class clazz, | |||
final String name, | |||
final String value, | |||
final TaskContext context ) | |||
throws ConfigurationException | |||
{ | |||
// Locate the configurer for this object | |||
final ObjectConfigurer configurer = getConfigurer( clazz ); | |||
// TODO - this ain't right, the validation is going to be screwed up | |||
final ConfigurationState state = configurer.startConfiguration( object ); | |||
// Set the attribute value | |||
try | |||
{ | |||
setAttribute( state, name, value, context ); | |||
} | |||
catch( final Exception ce ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-set-class-attribute.error", | |||
name, | |||
object.getClass().getName() ); | |||
throw new ConfigurationException( message, ce ); | |||
} | |||
// Finish up | |||
configurer.finishConfiguration( state ); | |||
} | |||
/** | |||
* Sets the text content for the element. | |||
*/ | |||
private void setContent( final ConfigurationState state, | |||
final String content, | |||
final TaskContext context ) | |||
throws Exception | |||
{ | |||
// Locate the content configurer | |||
final PropertyConfigurer contentConfigurer = state.getConfigurer().getContentConfigurer(); | |||
if( contentConfigurer == null ) | |||
{ | |||
throw new NoSuchPropertyException(); | |||
} | |||
// Set the content | |||
setValue( contentConfigurer, state, content, context ); | |||
} | |||
/** | |||
* Configures a property from a nested element. | |||
*/ | |||
private void configureElement( final ConfigurationState state, | |||
final Configuration element, | |||
final TaskContext context ) | |||
throws Exception | |||
{ | |||
final String elementName = element.getName(); | |||
if( elementName.toLowerCase().endsWith( "-ref" ) ) | |||
{ | |||
// A reference | |||
configureReference( state, element, context ); | |||
} | |||
else | |||
{ | |||
// An inline object | |||
configureInline( state, element, context ); | |||
} | |||
} | |||
/** | |||
* Configure a property from an inline object. | |||
*/ | |||
private void configureInline( final ConfigurationState state, | |||
final Configuration element, | |||
final TaskContext context ) | |||
throws Exception | |||
{ | |||
final String name = element.getName(); | |||
// Locate the configurer for the child element | |||
final PropertyConfigurer childConfigurer = | |||
getConfigurerFromName( state.getConfigurer(), name, true, true ); | |||
// Create & configure the child element | |||
final Object child = | |||
setupChild( state, element, context, childConfigurer ); | |||
// Set the child element | |||
childConfigurer.addValue( state, child ); | |||
} | |||
/** | |||
* Configures a property from a reference. | |||
*/ | |||
private void configureReference( final ConfigurationState state, | |||
final Configuration element, | |||
final TaskContext context ) | |||
throws Exception | |||
{ | |||
// Extract the id | |||
final String id = element.getAttribute( "id" ); | |||
if( 1 != element.getAttributeNames().length || | |||
0 != element.getChildren().length ) | |||
{ | |||
final String message = REZ.getString( "extra-config-for-ref.error" ); | |||
throw new ConfigurationException( message ); | |||
} | |||
// Set the property | |||
final String name = element.getName(); | |||
setReference( state, name, id, context, true ); | |||
} | |||
/** | |||
* Sets a property using a reference. | |||
*/ | |||
private void setReference( final ConfigurationState state, | |||
final String refName, | |||
final String unresolvedId, | |||
final TaskContext context, | |||
final boolean isAdder ) | |||
throws Exception | |||
{ | |||
// Adjust the name | |||
final String name = refName.substring( 0, refName.length() - 4 ); | |||
// Locate the configurer for the property | |||
final PropertyConfigurer configurer = | |||
getConfigurerFromName( state.getConfigurer(), name, false, isAdder ); | |||
// Resolve any props in the id | |||
String id = context.resolveValue( unresolvedId ).toString(); | |||
// Locate the referenced object | |||
Object ref = context.getProperty( id ); | |||
if( null == ref ) | |||
{ | |||
final String message = REZ.getString( "unknown-reference.error", id ); | |||
throw new ConfigurationException( message ); | |||
} | |||
// Convert the object, if necessary | |||
final Class type = configurer.getType(); | |||
if( !type.isInstance( ref ) ) | |||
{ | |||
try | |||
{ | |||
ref = m_converter.convert( type, ref, context ); | |||
} | |||
catch( ConverterException e ) | |||
{ | |||
final String message = REZ.getString( "mismatch-ref-types.error", id, name ); | |||
throw new ConfigurationException( message, e ); | |||
} | |||
} | |||
// Set the child element | |||
configurer.addValue( state, ref ); | |||
} | |||
/** | |||
* Sets an attribute value. | |||
*/ | |||
private void setAttribute( final ConfigurationState state, | |||
final String name, | |||
final String value, | |||
final TaskContext context ) | |||
throws Exception | |||
{ | |||
// Set the value | |||
final PropertyConfigurer property = | |||
getConfigurerFromName( state.getConfigurer(), name, false, false ); | |||
setValue( property, state, value, context ); | |||
} | |||
/** | |||
* Sets an attribute value, or an element's text content. | |||
*/ | |||
private void setValue( final PropertyConfigurer setter, | |||
final ConfigurationState state, | |||
final String value, | |||
final TaskContext context ) | |||
throws Exception | |||
{ | |||
// Resolve property references in the attribute value | |||
Object objValue = context.resolveValue( value ); | |||
// Convert the value to the appropriate type | |||
final Class type = setter.getType(); | |||
if( !type.isInstance( objValue ) ) | |||
{ | |||
objValue = m_converter.convert( type, objValue, context ); | |||
} | |||
// Set the value | |||
setter.addValue( state, objValue ); | |||
} | |||
/** | |||
* Locates the configurer for a particular class. | |||
*/ | |||
private ObjectConfigurer getConfigurer( final Class clazz ) | |||
throws ConfigurationException | |||
{ | |||
ObjectConfigurer configurer = | |||
(ObjectConfigurer)m_configurerCache.get( clazz ); | |||
if( null == configurer ) | |||
{ | |||
configurer = DefaultObjectConfigurer.getConfigurer( clazz ); | |||
m_configurerCache.put( clazz, configurer ); | |||
} | |||
return configurer; | |||
} | |||
/** | |||
* Creates and configures an inline object. | |||
*/ | |||
private Object setupChild( final ConfigurationState state, | |||
final Configuration element, | |||
final TaskContext context, | |||
final PropertyConfigurer childConfigurer ) | |||
throws Exception | |||
{ | |||
final String name = element.getName(); | |||
final Class type = childConfigurer.getType(); | |||
if( Configuration.class == type ) | |||
{ | |||
//special case where you have add...(Configuration) | |||
return element; | |||
} | |||
// Create an instance | |||
Object child = null; | |||
if( childConfigurer == state.getConfigurer().getTypedProperty() ) | |||
{ | |||
// Typed property | |||
child = createTypedObject( name, type ); | |||
} | |||
else | |||
{ | |||
// Named property | |||
child = createNamedObject( type ); | |||
} | |||
// Configure the object | |||
final Object object = child; | |||
configureObject( object, object.getClass(), element, context ); | |||
// Convert the object, if necessary | |||
if( !type.isInstance( child ) ) | |||
{ | |||
child = m_converter.convert( type, child, context ); | |||
} | |||
return child; | |||
} | |||
/** | |||
* Determines the property configurer to use for a particular element | |||
* or attribute. If the supplied name matches a property of the | |||
* class being configured, that property configurer is returned. If | |||
* the supplied name matches the role shorthand for the class' typed | |||
* property, then the typed property configurer is used. | |||
* | |||
* @param configurer The configurer for the class being configured. | |||
* @param name The attribute/element name. | |||
*/ | |||
private PropertyConfigurer getConfigurerFromName( final ObjectConfigurer configurer, | |||
final String name, | |||
boolean ignoreRoleName, | |||
final boolean isAdder ) | |||
throws Exception | |||
{ | |||
// Try a named property | |||
if( !isAdder ) | |||
{ | |||
PropertyConfigurer propertyConfigurer = configurer.getSetter( name ); | |||
if( propertyConfigurer != null ) | |||
{ | |||
return propertyConfigurer; | |||
} | |||
} | |||
else | |||
{ | |||
PropertyConfigurer propertyConfigurer = configurer.getAdder( name ); | |||
if( propertyConfigurer != null ) | |||
{ | |||
return propertyConfigurer; | |||
} | |||
// Try a typed property | |||
propertyConfigurer = configurer.getTypedProperty(); | |||
if( propertyConfigurer != null ) | |||
{ | |||
if( ignoreRoleName ) | |||
{ | |||
return propertyConfigurer; | |||
} | |||
else | |||
{ | |||
// Check the role name | |||
final RoleInfo roleInfo = | |||
m_roleManager.getRoleByType( propertyConfigurer.getType() ); | |||
if( roleInfo != null && name.equalsIgnoreCase( roleInfo.getShorthand() ) ) | |||
{ | |||
return propertyConfigurer; | |||
} | |||
} | |||
} | |||
} | |||
// Unknown prop | |||
throw new NoSuchPropertyException(); | |||
} | |||
/** | |||
* Creates an instance for a named property. | |||
*/ | |||
private Object createNamedObject( final Class type ) | |||
throws Exception | |||
{ | |||
// Map the expected type to a role. If found, instantiate the default | |||
// type for that role | |||
final RoleInfo roleInfo = m_roleManager.getRoleByType( type ); | |||
if( roleInfo != null ) | |||
{ | |||
final String typeName = roleInfo.getDefaultType(); | |||
if( typeName != null ) | |||
{ | |||
// Create the instance | |||
final TypeFactory factory = m_typeManager.getFactory( roleInfo.getName() ); | |||
return factory.create( typeName ); | |||
} | |||
} | |||
if( type.isInterface() ) | |||
{ | |||
// An interface - don't know how to instantiate it | |||
final String message = REZ.getString( "instantiate-interface.error", type.getName() ); | |||
throw new ConfigurationException( message ); | |||
} | |||
// Use the no-args constructor | |||
return createObject( type ); | |||
} | |||
/** | |||
* Creates an instance of the typed property. | |||
*/ | |||
private Object createTypedObject( final String name, | |||
final Class type ) | |||
throws Exception | |||
{ | |||
// Map the expected type to a role. If found, attempt to create | |||
// an instance | |||
final RoleInfo roleInfo = m_roleManager.getRoleByType( type ); | |||
if( roleInfo != null ) | |||
{ | |||
final TypeFactory factory = m_typeManager.getFactory( roleInfo.getName() ); | |||
if( factory.canCreate( name ) ) | |||
{ | |||
return factory.create( name ); | |||
} | |||
} | |||
// Use the generic 'data-type' role. | |||
final TypeFactory factory = m_typeManager.getFactory( DataType.ROLE ); | |||
if( !factory.canCreate( name ) ) | |||
{ | |||
throw new NoSuchPropertyException(); | |||
} | |||
return factory.create( name ); | |||
} | |||
/** | |||
* Utility method to instantiate an instance of the specified class. | |||
*/ | |||
private Object createObject( final Class type ) | |||
throws Exception | |||
{ | |||
try | |||
{ | |||
return type.newInstance(); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = | |||
REZ.getString( "create-object.error", | |||
type.getName() ); | |||
throw new ConfigurationException( message, e ); | |||
} | |||
} | |||
} |
@@ -1,395 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import java.lang.reflect.Method; | |||
import java.lang.reflect.Modifier; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
/** | |||
* An object configurer which uses reflection to determine the properties | |||
* of a class. | |||
* | |||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class DefaultObjectConfigurer | |||
implements ObjectConfigurer | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultObjectConfigurer.class ); | |||
private final Class m_class; | |||
/** | |||
* Adder property configurers. (For XML elements) | |||
*/ | |||
private final HashMap m_adders = new HashMap(); | |||
/** | |||
* Setter property configurers. (For XML attributes) | |||
*/ | |||
private final HashMap m_setters = new HashMap(); | |||
/** | |||
* The typed property configurer. | |||
*/ | |||
private PropertyConfigurer m_typedPropertyConfigurer; | |||
/** | |||
* Content configurer. | |||
*/ | |||
private PropertyConfigurer m_contentConfigurer; | |||
/** | |||
* Total number of properties. | |||
*/ | |||
private int m_propCount; | |||
/** | |||
* Creates an object configurer for a particular class. The newly | |||
* created configurer will not handle any attributes, elements, or content. | |||
* Use the various <code>enable</code> methods to enable handling of these. | |||
*/ | |||
private DefaultObjectConfigurer( final Class classInfo ) | |||
{ | |||
m_class = classInfo; | |||
} | |||
/** | |||
* Enables all properties and content handling. | |||
*/ | |||
private void enableAll() | |||
throws ConfigurationException | |||
{ | |||
enableSetters(); | |||
enableAdders(); | |||
enableTypedAdder(); | |||
enableContent(); | |||
} | |||
/** | |||
* Enables all setters. | |||
*/ | |||
private void enableSetters() | |||
throws ConfigurationException | |||
{ | |||
// Locate all the setter methods | |||
final Collection methods = findMethods( "set", false ); | |||
// Create a configurer for each setter | |||
final Iterator iterator = methods.iterator(); | |||
while( iterator.hasNext() ) | |||
{ | |||
final Method method = (Method)iterator.next(); | |||
final Class type = method.getParameterTypes()[ 0 ]; | |||
final String propName = extractName( 3, method.getName() ); | |||
final DefaultPropertyConfigurer setter = | |||
new DefaultPropertyConfigurer( getPropertyCount(), | |||
type, | |||
method, | |||
1 ); | |||
m_setters.put( propName, setter ); | |||
} | |||
} | |||
/** | |||
* Enables all adders. | |||
*/ | |||
private void enableAdders() | |||
throws ConfigurationException | |||
{ | |||
// Locate all the adder methods | |||
final Collection methods = findMethods( "add", false ); | |||
final Iterator iterator = methods.iterator(); | |||
while( iterator.hasNext() ) | |||
{ | |||
final Method method = (Method)iterator.next(); | |||
final String methodName = method.getName(); | |||
// Skip the text content method | |||
if( methodName.equals( "addContent" ) ) | |||
{ | |||
continue; | |||
} | |||
final Class type = method.getParameterTypes()[ 0 ]; | |||
final String propName = extractName( 3, methodName ); | |||
final DefaultPropertyConfigurer configurer = | |||
new DefaultPropertyConfigurer( getPropertyCount(), | |||
type, | |||
method, | |||
Integer.MAX_VALUE ); | |||
m_adders.put( propName, configurer ); | |||
} | |||
} | |||
/** | |||
* Enables the typed adder. | |||
*/ | |||
private void enableTypedAdder() | |||
throws ConfigurationException | |||
{ | |||
final Collection methods = findMethods( "add", true ); | |||
if( methods.size() == 0 ) | |||
{ | |||
return; | |||
} | |||
final Method method = (Method)methods.iterator().next(); | |||
final Class type = method.getParameterTypes()[ 0 ]; | |||
// TODO - this isn't necessary | |||
if( !type.isInterface() ) | |||
{ | |||
final String message = | |||
REZ.getString( "typed-adder-non-interface.error", | |||
m_class.getName(), | |||
type.getName() ); | |||
throw new ConfigurationException( message ); | |||
} | |||
m_typedPropertyConfigurer | |||
= new DefaultPropertyConfigurer( getPropertyCount(), | |||
type, | |||
method, | |||
Integer.MAX_VALUE ); | |||
} | |||
/** | |||
* Enables text content. | |||
*/ | |||
private void enableContent() | |||
throws ConfigurationException | |||
{ | |||
// Locate the 'addContent' methods, which return void, and take | |||
// a single parameter. | |||
final Collection methods = findMethods( "addContent", true ); | |||
if( methods.size() == 0 ) | |||
{ | |||
return; | |||
} | |||
final Method method = (Method)methods.iterator().next(); | |||
final Class type = method.getParameterTypes()[ 0 ]; | |||
m_contentConfigurer = new DefaultPropertyConfigurer( getPropertyCount(), | |||
type, | |||
method, | |||
1 ); | |||
} | |||
/** | |||
* Locate all methods whose name starts with a particular | |||
* prefix, and which are non-static, return void, and take a single | |||
* non-array parameter. If there are more than one matching methods of | |||
* a given name, the method that takes a String parameter (if any) is | |||
* ignored. If after that there are more than one matching methods of | |||
* a given name, an exception is thrown. | |||
* | |||
* @return Map from property name -> Method object for that property. | |||
*/ | |||
private Collection findMethods( final String prefix, | |||
final boolean exactMatch ) | |||
throws ConfigurationException | |||
{ | |||
final Map methods = new HashMap(); | |||
final List allMethods = findMethodsWithPrefix( prefix, exactMatch ); | |||
final Iterator iterator = allMethods.iterator(); | |||
while( iterator.hasNext() ) | |||
{ | |||
final Method method = (Method)iterator.next(); | |||
final String methodName = method.getName(); | |||
if( Void.TYPE != method.getReturnType() || | |||
1 != method.getParameterTypes().length || | |||
method.getParameterTypes()[ 0 ].isArray() ) | |||
{ | |||
continue; | |||
} | |||
// Extract property name | |||
final Class type = method.getParameterTypes()[ 0 ]; | |||
// Add to the adders map | |||
if( methods.containsKey( methodName ) ) | |||
{ | |||
final Method candidate = (Method)methods.get( methodName ); | |||
final Class currentType = candidate.getParameterTypes()[ 0 ]; | |||
// Ditch the string version, if any | |||
if( currentType != String.class && type == String.class ) | |||
{ | |||
// New type is string, and current type is not. Ignore | |||
// the new method | |||
continue; | |||
} | |||
else if( currentType != String.class || type == String.class ) | |||
{ | |||
// Both are string (which would be odd), or both are not string | |||
final String message = | |||
REZ.getString( "multiple-methods-for-element.error", | |||
m_class.getName(), | |||
methodName ); | |||
throw new ConfigurationException( message ); | |||
} | |||
// Else, current type is string, and new type is not, so | |||
// continue below, and replace the current method | |||
} | |||
methods.put( methodName, method ); | |||
} | |||
return methods.values(); | |||
} | |||
private int getPropertyCount() | |||
{ | |||
return m_propCount++; | |||
} | |||
/** | |||
* Locates the configurer for a particular class. | |||
*/ | |||
public static ObjectConfigurer getConfigurer( final Class classInfo ) | |||
throws ConfigurationException | |||
{ | |||
final DefaultObjectConfigurer configurer = new DefaultObjectConfigurer( classInfo ); | |||
configurer.enableAll(); | |||
return configurer; | |||
} | |||
/** | |||
* Starts the configuration of an object. | |||
*/ | |||
public ConfigurationState startConfiguration( Object object ) | |||
throws ConfigurationException | |||
{ | |||
return new ConfigurationState( this, object, getPropertyCount() ); | |||
} | |||
/** | |||
* Finishes the configuration of an object, performing any final | |||
* validation and type conversion. | |||
*/ | |||
public Object finishConfiguration( final ConfigurationState state ) | |||
throws ConfigurationException | |||
{ | |||
// Make sure there are no pending created objects | |||
final ConfigurationState defState = (ConfigurationState)state; | |||
return defState.getObject(); | |||
} | |||
/** | |||
* Returns a configurer for an element of this class. | |||
*/ | |||
public PropertyConfigurer getAdder( final String name ) | |||
{ | |||
return (PropertyConfigurer)m_adders.get( name ); | |||
} | |||
/** | |||
* Returns a configurer for an element of this class. | |||
*/ | |||
public PropertyConfigurer getSetter( final String name ) | |||
{ | |||
return (PropertyConfigurer)m_setters.get( name ); | |||
} | |||
/** | |||
* Returns a configurer for the typed property of this class. | |||
*/ | |||
public PropertyConfigurer getTypedProperty() | |||
{ | |||
return m_typedPropertyConfigurer; | |||
} | |||
/** | |||
* Returns a configurer for the content of this class. | |||
*/ | |||
public PropertyConfigurer getContentConfigurer() | |||
{ | |||
return m_contentConfigurer; | |||
} | |||
/** | |||
* Extracts a property name from a Java method name. | |||
* | |||
* <p>Removes the prefix, inserts '-' before each uppercase character | |||
* (except the first), then converts all to lowercase. | |||
*/ | |||
private String extractName( final int prefixLen, final String methodName ) | |||
{ | |||
final StringBuffer sb = new StringBuffer( methodName ); | |||
sb.delete( 0, prefixLen ); | |||
//Contains the index that we are up to in string buffer. | |||
//May not be equal to i as length of string buffer may change | |||
int index = 0; | |||
final int size = sb.length(); | |||
for( int i = 0; i < size; i++ ) | |||
{ | |||
char ch = sb.charAt( index ); | |||
if( Character.isUpperCase( ch ) ) | |||
{ | |||
if( index > 0 ) | |||
{ | |||
sb.insert( index, '-' ); | |||
index++; | |||
} | |||
sb.setCharAt( index, Character.toLowerCase( ch ) ); | |||
} | |||
index++; | |||
} | |||
return sb.toString(); | |||
} | |||
/** | |||
* Locates all non-static methods whose name starts with a particular | |||
* prefix. | |||
*/ | |||
private List findMethodsWithPrefix( final String prefix, | |||
final boolean exactMatch ) | |||
{ | |||
final ArrayList matches = new ArrayList(); | |||
final int prefixLen = prefix.length(); | |||
final Method[] methods = m_class.getMethods(); | |||
for( int i = 0; i < methods.length; i++ ) | |||
{ | |||
final Method method = methods[ i ]; | |||
final String methodName = method.getName(); | |||
if( Modifier.isStatic( method.getModifiers() ) ) | |||
{ | |||
continue; | |||
} | |||
if( methodName.length() < prefixLen || !methodName.startsWith( prefix ) ) | |||
{ | |||
continue; | |||
} | |||
if( exactMatch && methodName.length() != prefixLen ) | |||
{ | |||
continue; | |||
} | |||
matches.add( method ); | |||
} | |||
return matches; | |||
} | |||
} |
@@ -1,139 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Method; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
/** | |||
* The default property configurer implementation, which uses reflection to | |||
* create and set property values. | |||
* | |||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class DefaultPropertyConfigurer | |||
implements PropertyConfigurer | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultPropertyConfigurer.class ); | |||
private final int m_propertyIndex; | |||
private final Class m_type; | |||
private final Method m_method; | |||
private final int m_maxCount; | |||
public DefaultPropertyConfigurer( final int propIndex, | |||
final Class type, | |||
final Method method, | |||
final int maxCount ) | |||
{ | |||
m_propertyIndex = propIndex; | |||
if( type.isPrimitive() ) | |||
{ | |||
m_type = getComplexTypeFor( type ); | |||
} | |||
else | |||
{ | |||
m_type = type; | |||
} | |||
m_method = method; | |||
m_maxCount = maxCount; | |||
if( null == m_method ) | |||
{ | |||
throw new NullPointerException( "method" ); | |||
} | |||
} | |||
/** | |||
* Returns the type of the element. | |||
*/ | |||
public Class getType() | |||
{ | |||
return m_type; | |||
} | |||
/** | |||
* Adds a value for this property, to an object. | |||
*/ | |||
public void addValue( final ConfigurationState state, final Object value ) | |||
throws ConfigurationException | |||
{ | |||
final ConfigurationState defState = (ConfigurationState)state; | |||
// Check the property count | |||
if( defState.getPropertyCount( m_propertyIndex ) >= m_maxCount ) | |||
{ | |||
final String message = REZ.getString( "too-many-values.error" ); | |||
throw new ConfigurationException( message ); | |||
} | |||
defState.incPropertyCount( m_propertyIndex ); | |||
try | |||
{ | |||
// Add the value | |||
m_method.invoke( defState.getObject(), new Object[]{value} ); | |||
} | |||
catch( final InvocationTargetException ite ) | |||
{ | |||
final Throwable cause = ite.getTargetException(); | |||
throw new ConfigurationException( cause.getMessage(), cause ); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
throw new ConfigurationException( e.getMessage(), e ); | |||
} | |||
} | |||
/** | |||
* Determines the complex type for a prmitive type. | |||
*/ | |||
private Class getComplexTypeFor( final Class clazz ) | |||
{ | |||
if( String.class == clazz ) | |||
{ | |||
return String.class; | |||
} | |||
else if( Integer.TYPE.equals( clazz ) ) | |||
{ | |||
return Integer.class; | |||
} | |||
else if( Long.TYPE.equals( clazz ) ) | |||
{ | |||
return Long.class; | |||
} | |||
else if( Short.TYPE.equals( clazz ) ) | |||
{ | |||
return Short.class; | |||
} | |||
else if( Byte.TYPE.equals( clazz ) ) | |||
{ | |||
return Byte.class; | |||
} | |||
else if( Boolean.TYPE.equals( clazz ) ) | |||
{ | |||
return Boolean.class; | |||
} | |||
else if( Float.TYPE.equals( clazz ) ) | |||
{ | |||
return Float.class; | |||
} | |||
else if( Double.TYPE.equals( clazz ) ) | |||
{ | |||
return Double.class; | |||
} | |||
else | |||
{ | |||
final String message = REZ.getString( "no-complex-type.error", clazz.getName() ); | |||
throw new IllegalArgumentException( message ); | |||
} | |||
} | |||
} |
@@ -1,19 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
/** | |||
* A marker exception that is thrown when an unknown property is encountered. | |||
* | |||
* @author Adam Murdoch | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class NoSuchPropertyException | |||
extends Exception | |||
{ | |||
} |
@@ -1,75 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
/** | |||
* Configures objects of a particular class. | |||
* | |||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
interface ObjectConfigurer | |||
{ | |||
/** | |||
* Starts the configuration of an object. | |||
* | |||
* @param object The object about to be configured. | |||
* @return The state object, used to track type-specific state during | |||
* configuration. | |||
* @throws ConfigurationException On error starting the configuration. | |||
*/ | |||
ConfigurationState startConfiguration( Object object ) | |||
throws ConfigurationException; | |||
/** | |||
* Finishes the configuration of an object, performing any final | |||
* validation and type conversion. | |||
* | |||
* @param state The state object. | |||
* @return The configured object. | |||
* @throws ConfigurationException On error finishing the configurtion. | |||
*/ | |||
Object finishConfiguration( ConfigurationState state ) | |||
throws ConfigurationException; | |||
/** | |||
* Returns a configurer for a atribute property of this class. | |||
* | |||
* @param name The attribute name. | |||
* @return A configurer for the property, or null if the property is not | |||
* valid for this class. | |||
*/ | |||
PropertyConfigurer getSetter( String name ); | |||
/** | |||
* Returns a configurer for a element property of this class. | |||
* | |||
* @param name The element name. | |||
* @return A configurer for the property, or null if the property is not | |||
* valid for this class. | |||
*/ | |||
PropertyConfigurer getAdder( String name ); | |||
/** | |||
* Returns a configurer for the text content of this class. | |||
* | |||
* @return A configurer for the text content, or null if the class does not | |||
* support text content. | |||
*/ | |||
PropertyConfigurer getContentConfigurer(); | |||
/** | |||
* Returns a configurer for the typed property of this class. | |||
* | |||
* @return A configurer for the typed property, or null if the class | |||
* does not have a typed property. | |||
*/ | |||
PropertyConfigurer getTypedProperty(); | |||
} |
@@ -1,36 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
/** | |||
* Configures a property of an object. | |||
* TODO - axe createValue(). | |||
* | |||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
interface PropertyConfigurer | |||
{ | |||
/** | |||
* Returns the type of this property. | |||
*/ | |||
Class getType(); | |||
/** | |||
* Adds a value for this property, to an object. | |||
* | |||
* @param state The state object, representing the object being configured. | |||
* @param value The property value. This must be assignable to the type | |||
* returned by {@link #getType}. | |||
* @throws ConfigurationException If the property cannot be set. | |||
*/ | |||
void addValue( ConfigurationState state, Object value ) | |||
throws ConfigurationException; | |||
} |
@@ -1,39 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
/** | |||
* A marker exception. | |||
* | |||
* TODO - this should extend ConfigurationException, except it is final. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class ReportableConfigurationException | |||
extends Exception | |||
{ | |||
private ConfigurationException m_cause; | |||
public ReportableConfigurationException( String s ) | |||
{ | |||
m_cause = new ConfigurationException( s ); | |||
} | |||
public ReportableConfigurationException( String s, Throwable throwable ) | |||
{ | |||
m_cause = new ConfigurationException( s, throwable ); | |||
} | |||
public ConfigurationException getCause() | |||
{ | |||
return m_cause; | |||
} | |||
} |
@@ -1,17 +0,0 @@ | |||
create-object.error=Could not create an object of class {0}. | |||
extra-config-for-ref.error=A reference element can only include an "id" attribute. | |||
mismatch-ref-types.error=Could not convert reference "{0}" to the type expected for property "{1}". | |||
incompatible-element-types.error=Incompatible creator and adder/setter methods found in class {0} for property "{1}". | |||
multiple-methods-for-element.error=Multiple non-String {1}() methods found in class {0}. | |||
too-many-values.error=Too many values for this property. | |||
no-complex-type.error=Can not get complex type for non-primitive type {0}. | |||
no-such-attribute.error=Element <{0}> does not support attribute "{1}". | |||
bad-set-attribute.error=Could not set attribute "{1}" for element <{0}>. | |||
bad-set-class-attribute.error=Could not set attribute "{0}" for object of class {1}. | |||
no-such-element.error=Element <{0}> does not support nested <{1}> elements. | |||
no-content.error=Element <{0} does not support text content. | |||
bad-set-content.error=Could not set text content for element <{0}>. | |||
typed-adder-non-interface.error=The typed adder for class "{0}" must have a single parameter that is an interface rather than {1} which defines a class. | |||
create-typed-object.error=Could not create an object of type "{0}" of class {1}. | |||
unknown-reference.error=Could not find referenced object "{0}". | |||
bad-configure-element.error=Could not configure element <{0}>. |
@@ -1,70 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.converter; | |||
import org.apache.aut.converter.Converter; | |||
import org.apache.aut.converter.AbstractMasterConverter; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* Converter engine to handle converting between types. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultMasterConverter | |||
extends AbstractMasterConverter | |||
implements ConverterRegistry, Serviceable | |||
{ | |||
private TypeManager m_typeManager; | |||
/** | |||
* Retrieve relevent services needed to deploy. | |||
* | |||
* @param serviceManager the ServiceManager | |||
* @exception ServiceException if an error occurs | |||
*/ | |||
public void service( final ServiceManager serviceManager ) | |||
throws ServiceException | |||
{ | |||
m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||
} | |||
/** | |||
* Register a converter | |||
* | |||
* @param className the className of converter | |||
* @param source the source classname | |||
* @param destination the destination classname | |||
*/ | |||
public void registerConverter( final String className, | |||
final String source, | |||
final String destination ) | |||
{ | |||
super.registerConverter( className, source, destination ); | |||
} | |||
/** | |||
* Create an instance of converter with specified name. | |||
* | |||
* @param name the name of converter | |||
* @return the created converter instance | |||
* @throws Exception if converter can not be created. | |||
*/ | |||
protected Converter createConverter( final String name ) | |||
throws Exception | |||
{ | |||
final TypeFactory factory = m_typeManager.getFactory( Converter.ROLE ); | |||
return (Converter)factory.create( name ); | |||
} | |||
} |
@@ -1,289 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import java.io.File; | |||
import java.net.URL; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.aut.converter.Converter; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||
import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||
import org.apache.myrmidon.interfaces.deployer.ConverterDefinition; | |||
import org.apache.myrmidon.interfaces.deployer.Deployer; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* This class deploys roles, types and services from a typelib. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultDeployer | |||
extends AbstractLogEnabled | |||
implements Deployer, Serviceable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultDeployer.class ); | |||
// The components used to deploy | |||
private ConverterRegistry m_converterRegistry; | |||
private TypeManager m_typeManager; | |||
private RoleManager m_roleManager; | |||
private ClassLoaderManager m_classLoaderManager; | |||
/** Map from ClassLoader to the deployer for that class loader. */ | |||
private final Map m_classLoaderDeployers = new HashMap(); | |||
/** | |||
* Retrieve relevent services needed to deploy. | |||
* | |||
* @param serviceManager the ServiceManager | |||
* @exception ServiceException if an error occurs | |||
*/ | |||
public void service( final ServiceManager serviceManager ) | |||
throws ServiceException | |||
{ | |||
m_converterRegistry = (ConverterRegistry)serviceManager.lookup( ConverterRegistry.ROLE ); | |||
m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||
m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||
m_classLoaderManager = (ClassLoaderManager)serviceManager.lookup( ClassLoaderManager.ROLE ); | |||
} | |||
/** | |||
* Creates a child deployer. | |||
*/ | |||
public Deployer createChildDeployer( final ServiceManager componentManager ) | |||
throws ServiceException | |||
{ | |||
final DefaultDeployer child = new DefaultDeployer(); | |||
setupLogger( child ); | |||
child.service( componentManager ); | |||
return child; | |||
} | |||
/** | |||
* Returns the deployer for a ClassLoader, creating the deployer if | |||
* necessary. | |||
*/ | |||
public TypeDeployer createDeployer( final ClassLoader loader ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
return createDeployment( loader, null ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "deploy-from-classloader.error", loader ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
/** | |||
* Returns the deployer for a type library, creating the deployer if | |||
* necessary. | |||
*/ | |||
public TypeDeployer createDeployer( final File file ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
final ClassLoader classLoader = m_classLoaderManager.getClassLoader( file ); | |||
return createDeployment( classLoader, file.toURL() ); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "deploy-from-file.error", file ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
/** | |||
* Creates a deployer for a ClassLoader. | |||
*/ | |||
private Deployment createDeployment( final ClassLoader loader, | |||
final URL jarUrl ) | |||
throws Exception | |||
{ | |||
// Locate cached deployer, creating it if necessary | |||
Deployment deployment = (Deployment)m_classLoaderDeployers.get( loader ); | |||
if( deployment == null ) | |||
{ | |||
deployment = new Deployment( this, loader ); | |||
setupLogger( deployment ); | |||
deployment.loadDescriptors( jarUrl ); | |||
m_classLoaderDeployers.put( loader, deployment ); | |||
} | |||
return deployment; | |||
} | |||
/** | |||
* Deploys a service. | |||
*/ | |||
public void deployService( final Deployment deployment, | |||
final ServiceDefinition definition ) | |||
throws Exception | |||
{ | |||
final String roleShorthand = definition.getRoleShorthand(); | |||
final String roleName = getRole( roleShorthand ).getName(); | |||
final String factoryClassName = definition.getFactoryClass(); | |||
handleType( deployment, ServiceFactory.ROLE, roleName, factoryClassName ); | |||
} | |||
/** | |||
* Handles a type definition. | |||
*/ | |||
public void deployType( final Deployment deployment, | |||
final TypeDefinition typeDef ) | |||
throws Exception | |||
{ | |||
final String typeName = typeDef.getName(); | |||
final String roleShorthand = typeDef.getRole(); | |||
final String className = typeDef.getClassname(); | |||
if( null == className ) | |||
{ | |||
final String message = REZ.getString( "typedef.no-classname.error" ); | |||
throw new DeploymentException( message ); | |||
} | |||
if( typeDef instanceof ConverterDefinition ) | |||
{ | |||
// Validate the definition | |||
final ConverterDefinition converterDef = (ConverterDefinition)typeDef; | |||
final String srcClass = converterDef.getSourceType(); | |||
final String destClass = converterDef.getDestinationType(); | |||
if( null == srcClass ) | |||
{ | |||
final String message = REZ.getString( "converterdef.no-source.error" ); | |||
throw new DeploymentException( message ); | |||
} | |||
if( null == destClass ) | |||
{ | |||
final String message = REZ.getString( "converterdef.no-destination.error" ); | |||
throw new DeploymentException( message ); | |||
} | |||
// Deploy the converter | |||
handleConverter( deployment, className, srcClass, destClass ); | |||
} | |||
else | |||
{ | |||
// Validate the definition | |||
if( null == roleShorthand ) | |||
{ | |||
final String message = REZ.getString( "typedef.no-role.error" ); | |||
throw new DeploymentException( message ); | |||
} | |||
else if( null == typeName ) | |||
{ | |||
final String message = REZ.getString( "typedef.no-name.error" ); | |||
throw new DeploymentException( message ); | |||
} | |||
// Deploy general-purpose type | |||
final String roleName = getRole( roleShorthand ).getName(); | |||
handleType( deployment, roleName, typeName, className ); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = | |||
REZ.getString( "register-type.notice", roleShorthand, typeName ); | |||
getLogger().debug( message ); | |||
} | |||
} | |||
} | |||
/** | |||
* Handles a type definition. | |||
*/ | |||
private void handleType( final Deployment deployment, | |||
final String roleName, | |||
final String typeName, | |||
final String className ) | |||
throws Exception | |||
{ | |||
// TODO - detect duplicates | |||
final DefaultTypeFactory factory = deployment.getFactory( roleName ); | |||
factory.addNameClassMapping( typeName, className ); | |||
m_typeManager.registerType( roleName, typeName, factory ); | |||
} | |||
/** | |||
* Handles a converter definition. | |||
*/ | |||
private void handleConverter( final Deployment deployment, | |||
final String className, | |||
final String source, | |||
final String destination ) | |||
throws Exception | |||
{ | |||
m_converterRegistry.registerConverter( className, source, destination ); | |||
final DefaultTypeFactory factory = deployment.getFactory( Converter.ROLE ); | |||
factory.addNameClassMapping( className, className ); | |||
m_typeManager.registerType( Converter.ROLE, className, factory ); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = | |||
REZ.getString( "register-converter.notice", source, destination ); | |||
getLogger().debug( message ); | |||
} | |||
} | |||
/** | |||
* Handles a role definition. | |||
*/ | |||
public void deployRole( final Deployment deployment, | |||
final RoleDefinition roleDef ) | |||
throws Exception | |||
{ | |||
final String name = roleDef.getShortHand(); | |||
final String role = roleDef.getRoleName(); | |||
final Class type = deployment.getClassLoader().loadClass( role ); | |||
final RoleInfo roleInfo = new RoleInfo( role, name, type, null ); | |||
m_roleManager.addRole( roleInfo ); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String debugMessage = REZ.getString( "register-role.notice", role, name ); | |||
getLogger().debug( debugMessage ); | |||
} | |||
} | |||
/** | |||
* Locates a role, from its shorthand. | |||
*/ | |||
private RoleInfo getRole( final String roleShorthand ) | |||
throws DeploymentException | |||
{ | |||
final RoleInfo roleInfo = m_roleManager.getRoleByShorthandName( roleShorthand ); | |||
if( null == roleInfo ) | |||
{ | |||
final String message = REZ.getString( "unknown-role4name.error", roleShorthand ); | |||
throw new DeploymentException( message ); | |||
} | |||
return roleInfo; | |||
} | |||
} |
@@ -1,363 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import java.io.FileNotFoundException; | |||
import java.net.URL; | |||
import java.util.ArrayList; | |||
import java.util.Enumeration; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import javax.xml.parsers.SAXParser; | |||
import javax.xml.parsers.SAXParserFactory; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.SAXConfigurationHandler; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
import org.xml.sax.XMLReader; | |||
/** | |||
* This class deploys type libraries from a ClassLoader into a registry. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class Deployment | |||
extends AbstractLogEnabled | |||
implements TypeDeployer | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( Deployment.class ); | |||
private static final String TYPE_DESCRIPTOR_NAME = "META-INF/ant-descriptor.xml"; | |||
private static final String ROLE_DESCRIPTOR_NAME = "META-INF/ant-roles.xml"; | |||
private static final String SERVICE_DESCRIPTOR_NAME = "META-INF/ant-services.xml"; | |||
private ClassLoader m_classLoader; | |||
private DefaultDeployer m_deployer; | |||
private TypeDescriptor[] m_descriptors; | |||
private ServiceDescriptor[] m_services; | |||
// TODO - create and configure these in DefaultDeployer | |||
private DescriptorBuilder m_roleBuilder = new RoleDescriptorBuilder(); | |||
private DescriptorBuilder m_typeBuilder = new TypeDescriptorBuilder(); | |||
private DescriptorBuilder m_serviceBuilder = new ServiceDescriptorBuilder(); | |||
/** Map from role Class -> DefaultTypeFactory for that role. */ | |||
private Map m_factories = new HashMap(); | |||
public Deployment( final DefaultDeployer deployer, final ClassLoader classLoader ) | |||
{ | |||
m_deployer = deployer; | |||
m_classLoader = classLoader; | |||
} | |||
/** | |||
* Load the descriptors. Deploys all roles, then loads the descriptors | |||
* for, but does not deploy, all the types. | |||
* | |||
* @param jarUrl The URL for the typelib, used to locate the descriptors. | |||
* If null, the resources from the classloader are used. | |||
*/ | |||
public void loadDescriptors( final URL jarUrl ) | |||
throws Exception | |||
{ | |||
// Create a SAX parser to assemble the descriptors into Configuration | |||
// objects | |||
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||
final SAXParser saxParser = saxParserFactory.newSAXParser(); | |||
final XMLReader parser = saxParser.getXMLReader(); | |||
//parser.setFeature( "http://xml.org/sax/features/namespace-prefixes", false ); | |||
final SAXConfigurationHandler handler = new SAXConfigurationHandler(); | |||
parser.setContentHandler( handler ); | |||
parser.setErrorHandler( handler ); | |||
// Build the role descriptors | |||
final ArrayList roleUrls = locateResources( ROLE_DESCRIPTOR_NAME, jarUrl ); | |||
final ArrayList roleDescriptors = | |||
buildDescriptors( roleUrls, m_roleBuilder, parser, handler ); | |||
// Deploy the roles | |||
// TODO - need to defer this | |||
final int roleCount = roleDescriptors.size(); | |||
for( int i = 0; i < roleCount; i++ ) | |||
{ | |||
final RoleDescriptor descriptor = (RoleDescriptor)roleDescriptors.get( i ); | |||
deployRoles( descriptor ); | |||
} | |||
// Build the type descriptors | |||
final ArrayList typeUrls = locateResources( TYPE_DESCRIPTOR_NAME, jarUrl ); | |||
final ArrayList typeDescriptors = | |||
buildDescriptors( typeUrls, m_typeBuilder, parser, handler ); | |||
m_descriptors = (TypeDescriptor[])typeDescriptors.toArray | |||
( new TypeDescriptor[ typeDescriptors.size() ] ); | |||
// Build the service descriptors | |||
final ArrayList serviceUrls = locateResources( SERVICE_DESCRIPTOR_NAME, jarUrl ); | |||
final ArrayList serviceDescriptors = | |||
buildDescriptors( serviceUrls, m_serviceBuilder, parser, handler ); | |||
m_services = (ServiceDescriptor[])serviceDescriptors.toArray | |||
( new ServiceDescriptor[ serviceDescriptors.size() ] ); | |||
} | |||
/** | |||
* Returns the type factory for a role. | |||
*/ | |||
public DefaultTypeFactory getFactory( final String roleName ) | |||
{ | |||
DefaultTypeFactory factory = (DefaultTypeFactory)m_factories.get( roleName ); | |||
if( null == factory ) | |||
{ | |||
factory = new DefaultTypeFactory( m_classLoader ); | |||
m_factories.put( roleName, factory ); | |||
} | |||
return factory; | |||
} | |||
/** | |||
* Returns the classloader for this deployment. | |||
*/ | |||
public ClassLoader getClassLoader() | |||
{ | |||
return m_classLoader; | |||
} | |||
/** | |||
* Deploys everything in the type library. | |||
*/ | |||
public void deployAll() | |||
throws DeploymentException | |||
{ | |||
// Deploy types | |||
for( int i = 0; i < m_descriptors.length; i++ ) | |||
{ | |||
TypeDescriptor descriptor = m_descriptors[ i ]; | |||
deployTypes( descriptor ); | |||
} | |||
// Deploy services | |||
for( int i = 0; i < m_services.length; i++ ) | |||
{ | |||
final ServiceDescriptor descriptor = m_services[ i ]; | |||
deployServices( descriptor ); | |||
} | |||
} | |||
/** | |||
* Deploys a single type in the type library. | |||
*/ | |||
public void deployType( final String roleShorthand, final String typeName ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
// Locate the definition for the type | |||
for( int i = 0; i < m_descriptors.length; i++ ) | |||
{ | |||
final TypeDescriptor descriptor = m_descriptors[ i ]; | |||
final TypeDefinition[] definitions = descriptor.getDefinitions(); | |||
for( int j = 0; j < definitions.length; j++ ) | |||
{ | |||
TypeDefinition definition = definitions[ j ]; | |||
if( definition.getRole().equals( roleShorthand ) | |||
&& definition.getName().equals( typeName ) ) | |||
{ | |||
// Found the definition - deploy it. Note that we | |||
// keep looking for matching types, and let the deployer | |||
// deal with duplicates | |||
m_deployer.deployType( this, definition ); | |||
} | |||
} | |||
} | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "deploy-type.error", roleShorthand, typeName ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
/** | |||
* Deploys a single type from the type library. | |||
*/ | |||
public void deployType( final TypeDefinition typeDef ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
m_deployer.deployType( this, typeDef ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "deploy-type.error", | |||
typeDef.getRole(), typeDef.getName() ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
/** | |||
* Builds descriptors. | |||
*/ | |||
private ArrayList buildDescriptors( final ArrayList urls, | |||
final DescriptorBuilder builder, | |||
final XMLReader parser, | |||
final SAXConfigurationHandler handler ) | |||
throws Exception | |||
{ | |||
final ArrayList descriptors = new ArrayList(); | |||
final int size = urls.size(); | |||
for( int i = 0; i < size; i++ ) | |||
{ | |||
final String url = (String)urls.get( i ); | |||
// Parse the file | |||
parser.parse( url ); | |||
final TypelibDescriptor descriptor = | |||
builder.createDescriptor( handler.getConfiguration(), url ); | |||
descriptors.add( descriptor ); | |||
} | |||
return descriptors; | |||
} | |||
/** | |||
* Locates all resources of a particular name. | |||
*/ | |||
private ArrayList locateResources( final String resource, final URL jarUrl ) | |||
throws Exception | |||
{ | |||
final ArrayList urls = new ArrayList(); | |||
if( null != jarUrl ) | |||
{ | |||
final String systemID = "jar:" + jarUrl + "!/" + resource; | |||
try | |||
{ | |||
// Probe the resource | |||
final URL url = new URL( systemID ); | |||
url.openStream().close(); | |||
// Add to the list | |||
urls.add( systemID ); | |||
} | |||
catch( FileNotFoundException e ) | |||
{ | |||
// Ignore | |||
} | |||
} | |||
else | |||
{ | |||
final Enumeration enum = m_classLoader.getResources( resource ); | |||
while( enum.hasMoreElements() ) | |||
{ | |||
urls.add( enum.nextElement().toString() ); | |||
} | |||
} | |||
return urls; | |||
} | |||
/** | |||
* Deploys the roles from a role descriptor. | |||
*/ | |||
private void deployRoles( final RoleDescriptor descriptor ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = | |||
REZ.getString( "url-deploy-roles.notice", descriptor.getUrl() ); | |||
getLogger().debug( message ); | |||
} | |||
final RoleDefinition[] definitions = descriptor.getDefinitions(); | |||
for( int i = 0; i < definitions.length; i++ ) | |||
{ | |||
final RoleDefinition definition = definitions[ i ]; | |||
m_deployer.deployRole( this, definition ); | |||
} | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "deploy-roles.error", descriptor.getUrl() ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
/** | |||
* Deploys all types from a typelib descriptor. | |||
*/ | |||
private void deployTypes( final TypeDescriptor descriptor ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = | |||
REZ.getString( "url-deploy-types.notice", descriptor.getUrl() ); | |||
getLogger().debug( message ); | |||
} | |||
// Deploy all the types | |||
final TypeDefinition[] definitions = descriptor.getDefinitions(); | |||
for( int i = 0; i < definitions.length; i++ ) | |||
{ | |||
final TypeDefinition definition = definitions[ i ]; | |||
m_deployer.deployType( this, definition ); | |||
} | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "deploy-types.error", descriptor.getUrl() ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
/** | |||
* Deploys all services from a typelib descriptor. | |||
*/ | |||
private void deployServices( final ServiceDescriptor descriptor ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = | |||
REZ.getString( "url-deploy-services.notice", descriptor.getUrl() ); | |||
getLogger().debug( message ); | |||
} | |||
// Deploy the services | |||
final ServiceDefinition[] definitions = descriptor.getDefinitions(); | |||
for( int i = 0; i < definitions.length; i++ ) | |||
{ | |||
final ServiceDefinition definition = definitions[ i ]; | |||
m_deployer.deployService( this, definition ); | |||
} | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "deploy-services.error", descriptor.getUrl() ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
} |
@@ -1,27 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
/** | |||
* Builds a descriptor. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
interface DescriptorBuilder | |||
{ | |||
/** | |||
* Builds a descriptor from a set of configuration. | |||
*/ | |||
TypelibDescriptor createDescriptor( Configuration config, | |||
String descriptorUrl ) | |||
throws DeploymentException; | |||
} |
@@ -1,27 +0,0 @@ | |||
register-converter.notice=Registered converter that converts from {0} to {1}. | |||
register-type.notice=Registered type {0}/{1}. | |||
register-role.notice=Registered role {0} with shorthand name {1}. | |||
url-deploy-types.notice=Registering types from "{0}". | |||
url-deploy-roles.notice=Registering roles from "{0}". | |||
url-deploy-services.notice=Registering services from "{0}". | |||
deploy-from-classloader.error=Could not register types from ClassLoader. | |||
deploy-from-file.error=Could not register types from type library "{0}". | |||
deploy-roles.error=Could not register roles from "{0}". | |||
deploy-types.error=Could not register types from "{0}". | |||
deploy-services.error=Could not register services from "{0}". | |||
deploy-converter.error=Could not register converter that converts from {0} to {1}. | |||
deploy-type.error=Could not register type {0}/{1}. | |||
unknown-role4name.error=Unknown role "{0}". | |||
typedef.no-classname.error=Must specify the classname parameter. | |||
typedef.no-name.error=Must specify name parameter. | |||
typedef.no-role.error=Must specify type parameter. | |||
converterdef.no-source.error=Must specify the source-type parameter. | |||
converterdef.no-destination.error=Must specify the destination-type parameter. | |||
role-descriptor-version.error=Role descriptor version {0} is incompatible with current version {1}. | |||
build-role-descriptor.error=Could not build role descriptor from "{0}". | |||
type-descriptor-version.error=Type library descriptor version {0} is incompatible with current version {1}. | |||
build-type-descriptor.error=Could not build type library descriptor from "{0}". | |||
service-descriptor-version.error=Service descriptor version {0} is incompatible with current version {1}. | |||
build-service-descriptor.error=Could not build service descriptor from "{0}". | |||
@@ -1,36 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
/** | |||
* A role definition. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
*/ | |||
class RoleDefinition | |||
{ | |||
private final String m_roleName; | |||
private final String m_shortHand; | |||
public RoleDefinition( final String roleName, | |||
final String shortHand ) | |||
{ | |||
m_roleName = roleName; | |||
m_shortHand = shortHand; | |||
} | |||
public String getRoleName() | |||
{ | |||
return m_roleName; | |||
} | |||
public String getShortHand() | |||
{ | |||
return m_shortHand; | |||
} | |||
} |
@@ -1,45 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* A typelib role descriptor, which defines a set of roles. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class RoleDescriptor | |||
extends TypelibDescriptor | |||
{ | |||
private final List m_definitions = new ArrayList(); | |||
public RoleDescriptor( final String url ) | |||
{ | |||
super( url ); | |||
} | |||
/** | |||
* Returns the role definitions in the descriptor. | |||
*/ | |||
public RoleDefinition[] getDefinitions() | |||
{ | |||
return (RoleDefinition[])m_definitions.toArray | |||
( new RoleDefinition[ m_definitions.size() ] ); | |||
} | |||
/** | |||
* Adds a role definition to the descriptor. | |||
*/ | |||
public void addDefinition( final RoleDefinition def ) | |||
{ | |||
m_definitions.add( def ); | |||
} | |||
} |
@@ -1,70 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.Version; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
/** | |||
* Builds typelib role descriptors. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class RoleDescriptorBuilder | |||
implements DescriptorBuilder | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( RoleDescriptorBuilder.class ); | |||
private static final Version ROLE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||
/** | |||
* Builds a descriptor from a set of configuration. | |||
*/ | |||
public TypelibDescriptor createDescriptor( final Configuration config, | |||
final String url ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
// Check version | |||
final String versionString = config.getAttribute( "version" ); | |||
final Version version = Version.getVersion( versionString ); | |||
if( !ROLE_DESCRIPTOR_VERSION.complies( version ) ) | |||
{ | |||
final String message = REZ.getString( "role-descriptor-version.error", | |||
version, ROLE_DESCRIPTOR_VERSION ); | |||
throw new DeploymentException( message ); | |||
} | |||
// Assemble the descriptor | |||
final RoleDescriptor descriptor = new RoleDescriptor( url ); | |||
// Extract each of the role elements | |||
final Configuration[] types = config.getChildren( "role" ); | |||
for( int i = 0; i < types.length; i++ ) | |||
{ | |||
final String name = types[ i ].getAttribute( "shorthand" ); | |||
final String role = types[ i ].getAttribute( "name" ); | |||
final RoleDefinition roleDef = new RoleDefinition( role, name ); | |||
descriptor.addDefinition( roleDef ); | |||
} | |||
return descriptor; | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "build-role-descriptor.error", url ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
} |
@@ -1,56 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
/** | |||
* A service definition. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class ServiceDefinition | |||
{ | |||
private final String m_roleShorthand; | |||
private final String m_factoryClass; | |||
private final Configuration m_config; | |||
public ServiceDefinition( final String roleShorthand, | |||
final String factoryClass, | |||
final Configuration config ) | |||
{ | |||
m_roleShorthand = roleShorthand; | |||
m_factoryClass = factoryClass; | |||
m_config = config; | |||
} | |||
/** | |||
* Returns the role that the service implements. | |||
*/ | |||
public String getRoleShorthand() | |||
{ | |||
return m_roleShorthand; | |||
} | |||
/** | |||
* Returns the name of the factory class for creating the service. | |||
*/ | |||
public String getFactoryClass() | |||
{ | |||
return m_factoryClass; | |||
} | |||
/** | |||
* Returns the service configuration. | |||
*/ | |||
public Configuration getConfig() | |||
{ | |||
return m_config; | |||
} | |||
} |
@@ -1,39 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* A typelib service descriptor, which defines a set of services. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class ServiceDescriptor | |||
extends TypelibDescriptor | |||
{ | |||
private final List m_services = new ArrayList(); | |||
public ServiceDescriptor( final String url ) | |||
{ | |||
super( url ); | |||
} | |||
public ServiceDefinition[] getDefinitions() | |||
{ | |||
return (ServiceDefinition[])m_services.toArray | |||
( new ServiceDefinition[ m_services.size() ] ); | |||
} | |||
public void addDefinition( final ServiceDefinition definition ) | |||
{ | |||
m_services.add( definition ); | |||
} | |||
} |
@@ -1,72 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.Version; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
/** | |||
* Builds typelib service descriptors. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class ServiceDescriptorBuilder | |||
implements DescriptorBuilder | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( ServiceDescriptorBuilder.class ); | |||
private static final Version SERVICE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||
/** | |||
* Builds a descriptor from a set of configuration. | |||
*/ | |||
public TypelibDescriptor createDescriptor( final Configuration config, | |||
final String url ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
// Check version | |||
final String versionString = config.getAttribute( "version" ); | |||
final Version version = Version.getVersion( versionString ); | |||
if( !SERVICE_DESCRIPTOR_VERSION.complies( version ) ) | |||
{ | |||
final String message = REZ.getString( "service-descriptor-version.error", | |||
version, SERVICE_DESCRIPTOR_VERSION ); | |||
throw new DeploymentException( message ); | |||
} | |||
// Build the descriptor | |||
final ServiceDescriptor descriptor = new ServiceDescriptor( url ); | |||
// Add the service definitions | |||
final Configuration[] elements = config.getChildren(); | |||
for( int i = 0; i < elements.length; i++ ) | |||
{ | |||
final Configuration element = elements[ i ]; | |||
final String roleShorthand = element.getName(); | |||
final String factoryClassName = element.getAttribute( "factory" ); | |||
final ServiceDefinition definition = | |||
new ServiceDefinition( roleShorthand, factoryClassName, config ); | |||
descriptor.addDefinition( definition ); | |||
} | |||
return descriptor; | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "build-service-descriptor.error", url ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
} |
@@ -1,40 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||
/** | |||
* A typelib type descriptor, which defines a set of types. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class TypeDescriptor | |||
extends TypelibDescriptor | |||
{ | |||
private final List m_definitions = new ArrayList(); | |||
public TypeDescriptor( final String url ) | |||
{ | |||
super( url ); | |||
} | |||
public TypeDefinition[] getDefinitions() | |||
{ | |||
return (TypeDefinition[])m_definitions.toArray | |||
( new TypeDefinition[ m_definitions.size() ] ); | |||
} | |||
public void addDefinition( final TypeDefinition def ) | |||
{ | |||
m_definitions.add( def ); | |||
} | |||
} |
@@ -1,96 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.Version; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.myrmidon.interfaces.deployer.ConverterDefinition; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||
/** | |||
* Builds typelib type descriptors. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class TypeDescriptorBuilder | |||
implements DescriptorBuilder | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( TypeDescriptorBuilder.class ); | |||
private static final Version TYPE_DESCRIPTOR_VERSION = new Version( 1, 0, 0 ); | |||
/** | |||
* Builds a descriptor from a set of configuration. | |||
*/ | |||
public TypelibDescriptor createDescriptor( final Configuration config, | |||
final String url ) | |||
throws DeploymentException | |||
{ | |||
try | |||
{ | |||
// Check version | |||
final String versionString = config.getAttribute( "version" ); | |||
final Version version = Version.getVersion( versionString ); | |||
if( !TYPE_DESCRIPTOR_VERSION.complies( version ) ) | |||
{ | |||
final String message = REZ.getString( "type-descriptor-version.error", | |||
version, TYPE_DESCRIPTOR_VERSION ); | |||
throw new DeploymentException( message ); | |||
} | |||
// Assemble the descriptor | |||
final TypeDescriptor descriptor = new TypeDescriptor( url ); | |||
// Extract each of the types elements | |||
final Configuration[] typeEntries = config.getChild( "types" ).getChildren(); | |||
for( int i = 0; i < typeEntries.length; i++ ) | |||
{ | |||
final Configuration typeEntry = typeEntries[ i ]; | |||
final TypeDefinition typeDef = createTypeDefinition( typeEntry ); | |||
descriptor.addDefinition( typeDef ); | |||
} | |||
return descriptor; | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "build-type-descriptor.error", url ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
/** | |||
* Creates a type definition. | |||
*/ | |||
private TypeDefinition createTypeDefinition( final Configuration configuration ) | |||
throws ConfigurationException | |||
{ | |||
final String roleShorthand = configuration.getName(); | |||
if( roleShorthand.equals( "converter" ) ) | |||
{ | |||
// A converter definition | |||
final String className = configuration.getAttribute( "classname" ); | |||
final String source = configuration.getAttribute( "source" ); | |||
final String destination = configuration.getAttribute( "destination" ); | |||
return new ConverterDefinition( className, source, destination ); | |||
} | |||
else | |||
{ | |||
// A type definition | |||
final String typeName = configuration.getAttribute( "name" ); | |||
final String className = configuration.getAttribute( "classname" ); | |||
return new TypeDefinition( typeName, roleShorthand, className ); | |||
} | |||
} | |||
} |
@@ -1,32 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.deployer; | |||
/** | |||
* A descriptor from a typelib. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class TypelibDescriptor | |||
{ | |||
private final String m_url; | |||
protected TypelibDescriptor( final String url ) | |||
{ | |||
m_url = url; | |||
} | |||
/** | |||
* Returns the descriptor URL. | |||
*/ | |||
public String getUrl() | |||
{ | |||
return m_url; | |||
} | |||
} |
@@ -1,454 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.embeddor; | |||
import java.io.File; | |||
import java.io.FilenameFilter; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.aut.converter.Converter; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.excalibur.io.ExtensionFileFilter; | |||
import org.apache.avalon.excalibur.io.FileUtil; | |||
import org.apache.avalon.framework.CascadingException; | |||
import org.apache.avalon.framework.context.Contextualizable; | |||
import org.apache.avalon.framework.context.Context; | |||
import org.apache.avalon.framework.context.ContextException; | |||
import org.apache.avalon.framework.activity.Disposable; | |||
import org.apache.avalon.framework.activity.Initializable; | |||
import org.apache.avalon.framework.activity.Startable; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.parameters.Parameterizable; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||
import org.apache.myrmidon.interfaces.builder.ProjectBuilder; | |||
import org.apache.myrmidon.interfaces.classloader.ClassLoaderManager; | |||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||
import org.apache.myrmidon.interfaces.deployer.Deployer; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||
import org.apache.myrmidon.interfaces.embeddor.Embeddor; | |||
import org.apache.myrmidon.interfaces.executor.Executor; | |||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||
import org.apache.myrmidon.interfaces.executor.ExecutionContainer; | |||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.MultiSourceServiceManager; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||
import org.apache.myrmidon.listeners.ProjectListener; | |||
import org.apache.myrmidon.components.workspace.DefaultExecutionFrame; | |||
import org.apache.myrmidon.components.store.DefaultPropertyStore; | |||
/** | |||
* Default implementation of Embeddor. | |||
* Instantiate this to embed inside other applications. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultEmbeddor | |||
extends AbstractLogEnabled | |||
implements Embeddor, Contextualizable, Initializable, Startable, Disposable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultEmbeddor.class ); | |||
/** Package containing the default component implementations. */ | |||
private static final String PREFIX = "org.apache.myrmidon.components."; | |||
private Deployer m_deployer; | |||
private TypeManager m_typeManager; | |||
private MultiSourceServiceManager m_workspaceServiceManager; | |||
private List m_components = new ArrayList(); | |||
private DefaultServiceManager m_serviceManager = new DefaultServiceManager(); | |||
private Context m_context; | |||
/** | |||
* Setup basic properties of engine. | |||
* Called before init() and can be used to specify alternate components in system. | |||
*/ | |||
public void contextualize( final Context context ) throws ContextException | |||
{ | |||
m_context = context; | |||
} | |||
/** | |||
* Builds a project. | |||
*/ | |||
public Project createProject( final String location, | |||
final String type, | |||
final Parameters parameters ) | |||
throws Exception | |||
{ | |||
try | |||
{ | |||
String projectType = type; | |||
if( null == projectType ) | |||
{ | |||
projectType = FileUtil.getExtension( location ); | |||
} | |||
// TODO - reuse the project builders, or dispose them | |||
final ProjectBuilder builder = getProjectBuilder( projectType, parameters ); | |||
return builder.build( location ); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "create-project.error", location ); | |||
throw new CascadingException( message, e ); | |||
} | |||
} | |||
/** | |||
* Creates a project builder for a project type. | |||
*/ | |||
private ProjectBuilder getProjectBuilder( final String type, | |||
final Parameters parameters ) | |||
throws Exception | |||
{ | |||
final TypeFactory factory = m_typeManager.getFactory( ProjectBuilder.ROLE ); | |||
final ProjectBuilder builder = (ProjectBuilder)factory.create( type ); | |||
setupObject( builder, m_serviceManager, parameters ); | |||
return builder; | |||
} | |||
/** | |||
* Creates a workspace. | |||
*/ | |||
public Workspace createWorkspace( final Map properties ) | |||
throws Exception | |||
{ | |||
final Workspace workspace = | |||
(Workspace)createService( Workspace.class, PREFIX + "workspace.DefaultWorkspace" ); | |||
setupObject( workspace, m_workspaceServiceManager, null ); | |||
// Create the property store | |||
final PropertyStore propStore = createBaseStore( properties ); | |||
// Create an execution frame, and attach it to the workspace | |||
final ExecutionFrame frame = | |||
new DefaultExecutionFrame( getLogger(), | |||
propStore, | |||
m_workspaceServiceManager); | |||
( (ExecutionContainer)workspace ).setRootExecutionFrame( frame ); | |||
// TODO - should keep track of workspaces, to dispose them later | |||
return workspace; | |||
} | |||
/** | |||
* Creates a project listener. | |||
* | |||
* @param name The shorthand name of the listener. | |||
* @return the listener. | |||
*/ | |||
public ProjectListener createListener( final String name ) | |||
throws Exception | |||
{ | |||
final TypeFactory factory = m_typeManager.getFactory( ProjectListener.ROLE ); | |||
return (ProjectListener)factory.create( name ); | |||
} | |||
/** | |||
* Initialize the system. | |||
* | |||
* @exception Exception if an error occurs | |||
*/ | |||
public void initialize() | |||
throws Exception | |||
{ | |||
// setup the root components | |||
setupComponents(); | |||
// locate the components we need | |||
m_deployer = (Deployer)m_serviceManager.lookup( Deployer.ROLE ); | |||
m_typeManager = (TypeManager)m_serviceManager.lookup( TypeManager.ROLE ); | |||
// setup a service manager that creates the project services | |||
final ServiceManager projServiceManager | |||
= (ServiceManager)createService( ServiceManager.class, | |||
PREFIX + "service.InstantiatingServiceManager" ); | |||
setupObject( projServiceManager, m_serviceManager, null ); | |||
m_components.add( projServiceManager ); | |||
// setup a service manager to be used by workspaces | |||
m_workspaceServiceManager = new MultiSourceServiceManager(); | |||
m_workspaceServiceManager.add( projServiceManager ); | |||
m_workspaceServiceManager.add( m_serviceManager ); | |||
} | |||
public void start() | |||
throws Exception | |||
{ | |||
// Deploy all type libraries found in the classpath | |||
final ClassLoader libClassloader = getClass().getClassLoader(); | |||
final TypeDeployer typeDeployer = m_deployer.createDeployer( libClassloader ); | |||
typeDeployer.deployAll(); | |||
// Deploy all type libraries in the lib directory | |||
final ExtensionFileFilter filter = new ExtensionFileFilter( ".atl" ); | |||
final File[] taskLibDirs = (File[])m_context.get( "myrmidon.lib.path" ); | |||
deployFromDirectories( m_deployer, taskLibDirs, filter ); | |||
} | |||
/** | |||
* Stops the engine. | |||
*/ | |||
public void stop() | |||
{ | |||
//TODO - Undeploy all the tasks by killing ExecutionFrame??? | |||
} | |||
/** | |||
* Dispose engine. | |||
*/ | |||
public void dispose() | |||
{ | |||
// Dispose any disposable components | |||
for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | |||
{ | |||
Object component = iterator.next(); | |||
if( component instanceof Disposable ) | |||
{ | |||
final Disposable disposable = (Disposable)component; | |||
disposable.dispose(); | |||
} | |||
} | |||
// Ditch everything | |||
m_components = null; | |||
m_deployer = null; | |||
m_serviceManager = null; | |||
m_context = null; | |||
} | |||
/** | |||
* Create all required components. | |||
*/ | |||
private void setupComponents() | |||
throws Exception | |||
{ | |||
// Create the components | |||
createComponent( ExtensionManager.class, PREFIX + "extensions.DefaultExtensionManager" ); | |||
final Object converter = | |||
createComponent( Converter.class, PREFIX + "converter.DefaultMasterConverter" ); | |||
m_serviceManager.put( ConverterRegistry.ROLE, converter ); | |||
createComponent( Configurer.class, PREFIX + "configurer.DefaultConfigurer" ); | |||
createComponent( TypeManager.class, PREFIX + "type.DefaultTypeManager" ); | |||
createComponent( RoleManager.class, PREFIX + "role.DefaultRoleManager" ); | |||
createComponent( AspectManager.class, PREFIX + "aspect.DefaultAspectManager" ); | |||
createComponent( Deployer.class, PREFIX + "deployer.DefaultDeployer" ); | |||
createComponent( ClassLoaderManager.class, | |||
PREFIX + "classloader.DefaultClassLoaderManager" ); | |||
createComponent( Executor.class, PREFIX + "executor.AspectAwareExecutor" ); | |||
createComponent( PropertyResolver.class, PREFIX + "property.DefaultPropertyResolver" ); | |||
m_serviceManager.put( Embeddor.ROLE, this ); | |||
// Setup the components | |||
for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | |||
{ | |||
final Object component = iterator.next(); | |||
setupObject( component, m_serviceManager, null ); | |||
} | |||
} | |||
/** | |||
* Creates a component. | |||
*/ | |||
private Object createComponent( final Class roleType, | |||
final String defaultImpl ) | |||
throws Exception | |||
{ | |||
final Object component = createService( roleType, defaultImpl ); | |||
m_serviceManager.put( roleType.getName(), component ); | |||
m_components.add( component ); | |||
return component; | |||
} | |||
/** | |||
* Create a component that implements an interface. | |||
* | |||
* @param roleType the name of interface/type | |||
* @param defaultImpl the classname of the default implementation | |||
* @return the created object | |||
* @exception Exception if an error occurs | |||
*/ | |||
private Object createService( final Class roleType, final String defaultImpl ) | |||
throws Exception | |||
{ | |||
// TODO - need to be able to provide different implementations | |||
final String className = defaultImpl; | |||
try | |||
{ | |||
final Object object = Class.forName( className ).newInstance(); | |||
if( !roleType.isInstance( object ) ) | |||
{ | |||
final String message = REZ.getString( "bad-type.error", | |||
className, roleType.getName() ); | |||
throw new Exception( message ); | |||
} | |||
return object; | |||
} | |||
catch( final IllegalAccessException iae ) | |||
{ | |||
final String message = REZ.getString( "bad-ctor.error", | |||
roleType.getName(), className ); | |||
throw new Exception( message ); | |||
} | |||
catch( final InstantiationException ie ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-instantiate.error", roleType.getName(), className ); | |||
throw new Exception( message ); | |||
} | |||
catch( final ClassNotFoundException cnfe ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-class.error", roleType.getName(), className ); | |||
throw new Exception( message ); | |||
} | |||
} | |||
/** | |||
* Sets-up an object by running it through the log-enable, compose, | |||
* parameterise and initialise lifecycle stages. | |||
*/ | |||
private void setupObject( final Object object, | |||
final ServiceManager serviceManager, | |||
final Parameters parameters ) | |||
throws Exception | |||
{ | |||
setupLogger( object ); | |||
if(object instanceof Contextualizable ) | |||
{ | |||
( (Contextualizable)object ).contextualize( m_context ); | |||
} | |||
if( object instanceof Serviceable ) | |||
{ | |||
( (Serviceable)object ).service( serviceManager ); | |||
} | |||
if( parameters != null && object instanceof Parameterizable ) | |||
{ | |||
( (Parameterizable)object ).parameterize( parameters ); | |||
} | |||
if( object instanceof Initializable ) | |||
{ | |||
( (Initializable)object ).initialize(); | |||
} | |||
} | |||
/** | |||
* Deploys all type libraries in a directory. | |||
*/ | |||
private void deployFromDirectories( final Deployer deployer, | |||
final File[] directories, | |||
final FilenameFilter filter ) | |||
throws DeploymentException | |||
{ | |||
for( int i = 0; i < directories.length; i++ ) | |||
{ | |||
File directory = directories[i ]; | |||
final File[] files = directory.listFiles( filter ); | |||
if( null != files ) | |||
{ | |||
deployFiles( deployer, files ); | |||
} | |||
} | |||
} | |||
/** | |||
* Deploys a set of type libraries. | |||
*/ | |||
private void deployFiles( final Deployer deployer, final File[] files ) | |||
throws DeploymentException | |||
{ | |||
for( int i = 0; i < files.length; i++ ) | |||
{ | |||
final String filename = files[ i ].getName(); | |||
int index = filename.lastIndexOf( '.' ); | |||
if( -1 == index ) | |||
{ | |||
index = filename.length(); | |||
} | |||
try | |||
{ | |||
final File file = files[ i ].getCanonicalFile(); | |||
final TypeDeployer typeDeployer = deployer.createDeployer( file ); | |||
typeDeployer.deployAll(); | |||
} | |||
catch( final DeploymentException de ) | |||
{ | |||
throw de; | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "bad-filename.error", files[ i ] ); | |||
throw new DeploymentException( message, e ); | |||
} | |||
} | |||
} | |||
/** | |||
* Creates the root property store for a workspace | |||
*/ | |||
private PropertyStore createBaseStore( final Map properties ) | |||
throws Exception | |||
{ | |||
final DefaultPropertyStore store = new DefaultPropertyStore(); | |||
addToStore( store, properties ); | |||
//Add system properties so that they overide user-defined properties | |||
addToStore( store, System.getProperties() ); | |||
return store; | |||
} | |||
/** | |||
* Helper method to add values to a store. | |||
* | |||
* @param store the store | |||
* @param map the map of names->values | |||
*/ | |||
private void addToStore( final PropertyStore store, final Map map ) | |||
throws Exception | |||
{ | |||
final Iterator keys = map.keySet().iterator(); | |||
while( keys.hasNext() ) | |||
{ | |||
final String key = (String)keys.next(); | |||
final Object value = map.get( key ); | |||
store.setProperty( key, value ); | |||
} | |||
} | |||
} |
@@ -1,6 +0,0 @@ | |||
bad-type.error=Object {0} is not an instance of {1}. | |||
bad-ctor.error=Non-public constructor for {0} {1}. | |||
no-instantiate.error=Error instantiating class for {0} {1}. | |||
no-class.error=Could not find the class for {0} ({1}). | |||
bad-filename.error=Unable to retrieve filename for file {0}. | |||
create-project.error=Could not load the project definition from {0}. |
@@ -1,337 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.executor; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.avalon.framework.configuration.DefaultConfiguration; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.api.Task; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||
/** | |||
* The AspectAwareExecutor executes the tasks but also calls | |||
* the aspects helpers. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class AspectAwareExecutor | |||
extends DefaultExecutor | |||
implements Serviceable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( AspectAwareExecutor.class ); | |||
private static final Configuration[] EMPTY_ELEMENTS = new Configuration[ 0 ]; | |||
private AspectManager m_aspectManager; | |||
/** | |||
* Retrieve relevent services. | |||
* | |||
* @param serviceManager the ServiceManager | |||
* @exception ServiceException if an error occurs | |||
*/ | |||
public void service( final ServiceManager serviceManager ) | |||
throws ServiceException | |||
{ | |||
m_aspectManager = (AspectManager)serviceManager.lookup( AspectManager.ROLE ); | |||
} | |||
public void execute( final Configuration taskModel, final ExecutionFrame frame ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
executeTask( taskModel, frame ); | |||
} | |||
catch( final TaskException te ) | |||
{ | |||
final boolean isError = getAspectManager().error( te ); | |||
if( !isError ) | |||
{ | |||
throw te; | |||
} | |||
} | |||
} | |||
private void executeTask( final Configuration model, | |||
final ExecutionFrame frame ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
Configuration taskModel = getAspectManager().preCreate( model ); | |||
taskModel = prepareAspects( taskModel ); | |||
final String taskName = taskModel.getName(); | |||
debug( "creating.notice", taskName ); | |||
final Task task = doCreateTask( taskName, frame ); | |||
getAspectManager().postCreate( task ); | |||
debug( "logger.notice", taskName ); | |||
final Logger logger = frame.getLogger(); | |||
getAspectManager().preLogEnabled( logger ); | |||
debug( "contextualizing.notice", taskName ); | |||
final TaskContext context = doCreateContext( frame ); | |||
doContextualize( task, taskModel, context, frame ); | |||
debug( "configuring.notice", taskName ); | |||
getAspectManager().preConfigure( taskModel ); | |||
doConfigure( task, taskModel, context, frame ); | |||
debug( "executing.notice", taskName ); | |||
getAspectManager().preExecute(); | |||
doExecute( taskModel, task ); | |||
getAspectManager().preDestroy(); | |||
} | |||
catch( Exception e ) | |||
{ | |||
// Wrap in generic error message | |||
final String message = REZ.getString( "execute.error", | |||
model.getName(), | |||
model.getLocation() ); | |||
throw new TaskException( message, e ); | |||
} | |||
} | |||
protected void doExecute( final Configuration taskModel, final Task task ) | |||
throws TaskException | |||
{ | |||
task.execute(); | |||
} | |||
//TODO: Extract and clean taskModel here. | |||
//Get all parameters from model and provide to appropriate aspect. | |||
//aspect( final Parameters parameters, final Configuration[] elements ) | |||
private final Configuration prepareAspects( final Configuration taskModel ) | |||
throws TaskException | |||
{ | |||
final DefaultConfiguration newTaskModel = | |||
new DefaultConfiguration( taskModel.getName(), taskModel.getLocation() ); | |||
final HashMap parameterMap = new HashMap(); | |||
final HashMap elementMap = new HashMap(); | |||
processAttributes( taskModel, newTaskModel, parameterMap ); | |||
processElements( taskModel, newTaskModel, elementMap ); | |||
try | |||
{ | |||
newTaskModel.setValue( taskModel.getValue() ); | |||
} | |||
catch( final ConfigurationException cee ) | |||
{ | |||
//Will never occur | |||
} | |||
dispatchAspectsSettings( parameterMap, elementMap ); | |||
checkForUnusedSettings( parameterMap, elementMap ); | |||
return newTaskModel; | |||
} | |||
private final void dispatchAspectsSettings( final HashMap parameterMap, | |||
final HashMap elementMap ) | |||
throws TaskException | |||
{ | |||
final String[] names = getAspectManager().getNames(); | |||
for( int i = 0; i < names.length; i++ ) | |||
{ | |||
final ArrayList elementList = (ArrayList)elementMap.remove( names[ i ] ); | |||
Parameters parameters = (Parameters)parameterMap.remove( names[ i ] ); | |||
if( null == parameters ) | |||
{ | |||
parameters = Parameters.EMPTY_PARAMETERS; | |||
} | |||
Configuration[] elements = null; | |||
if( null == elementList ) | |||
{ | |||
elements = EMPTY_ELEMENTS; | |||
} | |||
else | |||
{ | |||
elements = (Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||
} | |||
dispatch( names[ i ], parameters, elements ); | |||
} | |||
} | |||
private final void checkForUnusedSettings( final HashMap parameterMap, | |||
final HashMap elementMap ) | |||
throws TaskException | |||
{ | |||
if( 0 != parameterMap.size() ) | |||
{ | |||
final String[] namespaces = | |||
(String[])parameterMap.keySet().toArray( new String[ 0 ] ); | |||
for( int i = 0; i < namespaces.length; i++ ) | |||
{ | |||
final String namespace = namespaces[ i ]; | |||
final Parameters parameters = (Parameters)parameterMap.get( namespace ); | |||
final ArrayList elementList = (ArrayList)elementMap.remove( namespace ); | |||
Configuration[] elements = null; | |||
if( null == elementList ) | |||
{ | |||
elements = EMPTY_ELEMENTS; | |||
} | |||
else | |||
{ | |||
elements = (Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||
} | |||
unusedSetting( namespace, parameters, elements ); | |||
} | |||
} | |||
if( 0 != elementMap.size() ) | |||
{ | |||
final String[] namespaces = | |||
(String[])elementMap.keySet().toArray( new String[ 0 ] ); | |||
for( int i = 0; i < namespaces.length; i++ ) | |||
{ | |||
final String namespace = namespaces[ i ]; | |||
final ArrayList elementList = (ArrayList)elementMap.remove( namespace ); | |||
final Configuration[] elements = | |||
(Configuration[])elementList.toArray( EMPTY_ELEMENTS ); | |||
unusedSetting( namespace, Parameters.EMPTY_PARAMETERS, elements ); | |||
} | |||
} | |||
} | |||
private void unusedSetting( final String namespace, | |||
final Parameters parameters, | |||
final Configuration[] elements ) | |||
throws TaskException | |||
{ | |||
final String message = | |||
REZ.getString( "unused-settings.error", | |||
namespace, | |||
Integer.toString( parameters.getNames().length ), | |||
Integer.toString( elements.length ) ); | |||
throw new TaskException( message ); | |||
} | |||
private void dispatch( final String namespace, | |||
final Parameters parameters, | |||
final Configuration[] elements ) | |||
throws TaskException | |||
{ | |||
getAspectManager().dispatchAspectSettings( namespace, parameters, elements ); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = | |||
REZ.getString( "dispatch-settings.notice", | |||
namespace, | |||
Integer.toString( parameters.getNames().length ), | |||
Integer.toString( elements.length ) ); | |||
getLogger().debug( message ); | |||
} | |||
} | |||
private final void processElements( final Configuration taskModel, | |||
final DefaultConfiguration newTaskModel, | |||
final HashMap map ) | |||
{ | |||
final Configuration[] elements = taskModel.getChildren(); | |||
for( int i = 0; i < elements.length; i++ ) | |||
{ | |||
final String name = elements[ i ].getName(); | |||
final int index = name.indexOf( ':' ); | |||
if( -1 == index ) | |||
{ | |||
newTaskModel.addChild( elements[ i ] ); | |||
} | |||
else | |||
{ | |||
final String namespace = name.substring( 0, index ); | |||
final ArrayList elementSet = getElements( namespace, map ); | |||
elementSet.add( elements[ i ] ); | |||
} | |||
} | |||
} | |||
private final void processAttributes( final Configuration taskModel, | |||
final DefaultConfiguration newTaskModel, | |||
final HashMap map ) | |||
{ | |||
final String[] attributes = taskModel.getAttributeNames(); | |||
for( int i = 0; i < attributes.length; i++ ) | |||
{ | |||
final String name = attributes[ i ]; | |||
final String value = taskModel.getAttribute( name, null ); | |||
final int index = name.indexOf( ':' ); | |||
if( -1 == index ) | |||
{ | |||
newTaskModel.setAttribute( name, value ); | |||
} | |||
else | |||
{ | |||
final String namespace = name.substring( 0, index ); | |||
final String localName = name.substring( index + 1 ); | |||
final Parameters parameters = getParameters( namespace, map ); | |||
parameters.setParameter( localName, value ); | |||
} | |||
} | |||
} | |||
private final ArrayList getElements( final String namespace, final HashMap map ) | |||
{ | |||
ArrayList elements = (ArrayList)map.get( namespace ); | |||
if( null == elements ) | |||
{ | |||
elements = new ArrayList(); | |||
map.put( namespace, elements ); | |||
} | |||
return elements; | |||
} | |||
private final Parameters getParameters( final String namespace, final HashMap map ) | |||
{ | |||
Parameters parameters = (Parameters)map.get( namespace ); | |||
if( null == parameters ) | |||
{ | |||
parameters = new Parameters(); | |||
map.put( namespace, parameters ); | |||
} | |||
return parameters; | |||
} | |||
private final AspectManager getAspectManager() | |||
{ | |||
return m_aspectManager; | |||
} | |||
} |
@@ -1,141 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.executor; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.myrmidon.api.Task; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.components.workspace.DefaultTaskContext; | |||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||
import org.apache.myrmidon.interfaces.executor.Executor; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* The basic executor that just executes the tasks. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultExecutor | |||
extends AbstractLogEnabled | |||
implements Executor | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultExecutor.class ); | |||
/** | |||
* Executes a task. | |||
*/ | |||
public void execute( final Configuration taskModel, final ExecutionFrame frame ) | |||
throws TaskException | |||
{ | |||
final String taskName = taskModel.getName(); | |||
try | |||
{ | |||
debug( "creating.notice", taskName ); | |||
final Task task = doCreateTask( taskName, frame ); | |||
debug( "contextualizing.notice", taskName ); | |||
final TaskContext context = doCreateContext( frame ); | |||
doContextualize( task, taskModel, context, frame ); | |||
debug( "configuring.notice", taskName ); | |||
doConfigure( task, taskModel, context, frame ); | |||
debug( "executing.notice", taskName ); | |||
task.execute(); | |||
} | |||
catch( Exception e ) | |||
{ | |||
// Wrap in generic error message | |||
final String message = REZ.getString( "execute.error", | |||
taskName, taskModel.getLocation() ); | |||
throw new TaskException( message, e ); | |||
} | |||
} | |||
protected final void debug( final String key, final String taskName ) | |||
{ | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = REZ.getString( key, taskName ); | |||
getLogger().debug( message ); | |||
} | |||
} | |||
/** | |||
* Creates a context for the task. | |||
*/ | |||
protected TaskContext doCreateContext( final ExecutionFrame frame ) | |||
{ | |||
// TODO - need to deactivate the context once the task has finished | |||
// executing | |||
return new DefaultTaskContext( frame.getServiceManager(), | |||
frame.getLogger(), | |||
frame.getProperties() ); | |||
} | |||
/** | |||
* Creates a task instance. | |||
*/ | |||
protected final Task doCreateTask( final String name, final ExecutionFrame frame ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
final TypeManager typeManager = (TypeManager)frame.getServiceManager().lookup( TypeManager.ROLE ); | |||
final TypeFactory factory = typeManager.getFactory( Task.ROLE ); | |||
return (Task)factory.create( name ); | |||
} | |||
catch( final Exception te ) | |||
{ | |||
final String message = REZ.getString( "create.error", name ); | |||
throw new TaskException( message, te ); | |||
} | |||
} | |||
/** | |||
* Configures a task instance. | |||
*/ | |||
protected final void doConfigure( final Task task, | |||
final Configuration taskModel, | |||
final TaskContext taskContext, | |||
final ExecutionFrame frame ) | |||
throws Exception | |||
{ | |||
final Configurer configurer = (Configurer)frame.getServiceManager().lookup( Configurer.ROLE ); | |||
configurer.configureElement( task, taskModel, taskContext ); | |||
} | |||
/** | |||
* Sets the context for a task. | |||
*/ | |||
protected final void doContextualize( final Task task, | |||
final Configuration taskModel, | |||
final TaskContext taskContext, | |||
final ExecutionFrame frame ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
task.contextualize( taskContext ); | |||
} | |||
catch( final Throwable throwable ) | |||
{ | |||
final String message = | |||
REZ.getString( "contextualize.error", taskModel.getName() ); | |||
throw new TaskException( message, throwable ); | |||
} | |||
} | |||
} |
@@ -1,81 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.executor; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.myrmidon.api.Task; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
* An executor that just displays the tasks rather than executing them. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class PrintingExecutor | |||
extends AspectAwareExecutor | |||
{ | |||
protected void doExecute( final Configuration taskModel, final Task task ) | |||
throws TaskException | |||
{ | |||
final StringBuffer sb = new StringBuffer(); | |||
printConfiguration( taskModel, 0, sb ); | |||
System.out.println( sb.toString() ); | |||
} | |||
private void printConfiguration( final Configuration taskModel, | |||
final int level, | |||
final StringBuffer sb ) | |||
{ | |||
for( int i = 0; i < level; i++ ) | |||
{ | |||
sb.append( ' ' ); | |||
} | |||
sb.append( '<' ); | |||
sb.append( taskModel.getName() ); | |||
final String[] names = taskModel.getAttributeNames(); | |||
for( int i = 0; i < names.length; i++ ) | |||
{ | |||
final String name = names[ i ]; | |||
final String value = taskModel.getAttribute( name, null ); | |||
sb.append( ' ' ); | |||
sb.append( name ); | |||
sb.append( "=\"" ); | |||
sb.append( value ); | |||
sb.append( '\"' ); | |||
} | |||
final Configuration[] children = taskModel.getChildren(); | |||
if( 0 == children.length ) | |||
{ | |||
sb.append( "/>\n" ); | |||
} | |||
else | |||
{ | |||
sb.append( ">\n" ); | |||
for( int i = 0; i < children.length; i++ ) | |||
{ | |||
printConfiguration( children[ i ], level + 1, sb ); | |||
} | |||
for( int i = 0; i < level; i++ ) | |||
{ | |||
sb.append( ' ' ); | |||
} | |||
sb.append( "</" ); | |||
sb.append( taskModel.getName() ); | |||
sb.append( ">\n" ); | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
creating.notice=Creating {0}. | |||
contextualizing.notice=Contextualizing {0}. | |||
configuring.notice=Configuring {0}. | |||
executing.notice=Executing {0}. | |||
create.error=Could not create task <{0}>. | |||
contextualize.error=Could not set the context for task <{0}>. | |||
execute.error={1}: Could not execute task <{0}>. | |||
unused-settings.error=Unused aspect settings for namespace {0} (parameterCount={1} elementCount={2}). | |||
dispatch-settings.notice=Dispatching Aspect Settings to namespace {0} (parameterCount={1} elementCount={2}). |
@@ -1,162 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.extensions; | |||
import java.io.File; | |||
import org.apache.avalon.excalibur.extension.DefaultPackageRepository; | |||
import org.apache.avalon.excalibur.extension.Extension; | |||
import org.apache.avalon.excalibur.extension.OptionalPackage; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.activity.Disposable; | |||
import org.apache.avalon.framework.activity.Initializable; | |||
import org.apache.avalon.framework.context.Context; | |||
import org.apache.avalon.framework.context.ContextException; | |||
import org.apache.avalon.framework.context.Contextualizable; | |||
import org.apache.avalon.framework.logger.LogEnabled; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||
/** | |||
* PhoenixPackageRepository | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultExtensionManager | |||
extends DefaultPackageRepository | |||
implements LogEnabled, Contextualizable, Initializable, Disposable, ExtensionManager | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultExtensionManager.class ); | |||
/** | |||
* The standard location of tools.jar for IBM/Sun JDKs. | |||
*/ | |||
private static final String TOOLS_JAR = | |||
File.separator + "lib" + File.separator + "tools.jar"; | |||
/** | |||
* The path relative to JRE in which tools.jar is located. | |||
*/ | |||
private static final String DEBIAN_TOOLS_JAR = | |||
File.separator + ".." + File.separator + "j2sdk1.3" + | |||
File.separator + "lib" + File.separator + "tools.jar"; | |||
private Logger m_logger; | |||
private File[] m_path; | |||
public DefaultExtensionManager() | |||
{ | |||
super( new File[ 0 ] ); | |||
} | |||
public DefaultExtensionManager( final File[] path ) | |||
{ | |||
super( path ); | |||
} | |||
public void enableLogging( final Logger logger ) | |||
{ | |||
m_logger = logger; | |||
} | |||
public void contextualize( final Context context ) throws ContextException | |||
{ | |||
m_path = (File[])context.get( "myrmidon.ext.path" ); | |||
} | |||
public void initialize() | |||
throws Exception | |||
{ | |||
setPath( m_path ); | |||
scanPath(); | |||
// Add the JVM's tools.jar as an extension | |||
final Extension extension = createToolsExtension(); | |||
final File jar = getToolsJar(); | |||
final Extension[] available = new Extension[]{extension}; | |||
final Extension[] required = new Extension[ 0 ]; | |||
final OptionalPackage toolsPackage = new OptionalPackage( jar, available, required ); | |||
cacheOptionalPackage( toolsPackage ); | |||
} | |||
public void dispose() | |||
{ | |||
clearCache(); | |||
} | |||
/** | |||
* Locates the optional package which best matches a required extension. | |||
* | |||
* @param extension the extension to locate an optional package | |||
* @return the optional package, or null if not found. | |||
*/ | |||
public OptionalPackage getOptionalPackage( final Extension extension ) | |||
{ | |||
final OptionalPackage[] packages = getOptionalPackages( extension ); | |||
if( null == packages || 0 == packages.length ) return null; | |||
//TODO: Use heurisitic to find which is best package | |||
return packages[ 0 ]; | |||
} | |||
protected void debug( final String message ) | |||
{ | |||
m_logger.debug( message ); | |||
} | |||
private File getToolsJar() | |||
throws Exception | |||
{ | |||
final String javaHome = System.getProperty( "java.home" ); | |||
String jdkHome; | |||
if( javaHome.endsWith( "jre" ) ) | |||
{ | |||
jdkHome = javaHome.substring( 0, javaHome.length() - 4 ); | |||
} | |||
else | |||
{ | |||
jdkHome = javaHome; | |||
} | |||
//We need to search through a few locations to locate tools.jar | |||
File tools = new File( jdkHome + TOOLS_JAR ); | |||
if( tools.exists() ) | |||
{ | |||
return tools; | |||
} | |||
//The path to tools.jar. In some cases $JRE_HOME is not equal to | |||
//$JAVA_HOME/jre. For example, on Debian, IBM's j2sdk1.3 .deb puts | |||
//the JRE in /usr/lib/j2sdk1.3, and the JDK in /usr/lib/j2re1.3, | |||
//tools.jar=${java.home}/../j2sdk1.3/lib/tools.jar | |||
tools = new File( jdkHome + DEBIAN_TOOLS_JAR ); | |||
if( !tools.exists() ) | |||
{ | |||
final String message = REZ.getString( "extension.missing-tools.error" ); | |||
throw new Exception( message ); | |||
} | |||
return tools; | |||
} | |||
private static Extension createToolsExtension() | |||
{ | |||
return new Extension( "com.sun.tools", | |||
"1.0", | |||
"com.sun", | |||
"1.0", | |||
"com.sun", | |||
"com.sun", | |||
null ); | |||
} | |||
} |
@@ -1,49 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.property; | |||
import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.api.TaskContext; | |||
/** | |||
* A {@link PropertyResolver} implementation which resolves properties | |||
* as per Ant1, ignoring undefined properties. | |||
* | |||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
* @version $Revision$ $Date$ | |||
* | |||
* @ant.type type="property-resolver" name="classic" | |||
*/ | |||
public class ClassicPropertyResolver | |||
extends DefaultPropertyResolver | |||
implements PropertyResolver | |||
{ | |||
/** | |||
* Retrieve a value from the specified context using the specified key. | |||
* If there is no such value, returns the original property reference. | |||
* | |||
* @param propertyName the name of the property to retrieve | |||
* @param context the set of known properties | |||
*/ | |||
protected Object getPropertyValue( final String propertyName, | |||
final TaskContext context ) | |||
throws TaskException | |||
{ | |||
final Object value = context.getProperty( propertyName ); | |||
if( value != null ) | |||
{ | |||
return value; | |||
} | |||
else | |||
{ | |||
return "${" + propertyName + "}"; | |||
} | |||
} | |||
} |
@@ -1,290 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.property; | |||
import org.apache.aut.converter.Converter; | |||
import org.apache.aut.converter.ConverterException; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||
/** | |||
* Base class for PropertyResolver implementations. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
* @version $Revision$ $Date$ | |||
* | |||
* @ant.type type="property-resolver" name="default" | |||
*/ | |||
public class DefaultPropertyResolver | |||
implements PropertyResolver, Serviceable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultPropertyResolver.class ); | |||
private Converter m_converter; | |||
public void service( final ServiceManager serviceManager ) throws ServiceException | |||
{ | |||
m_converter = (Converter)serviceManager.lookup( Converter.ROLE ); | |||
} | |||
/** | |||
* Resolve a string property. This evaluates all property | |||
* substitutions based on specified context. | |||
* | |||
* If the content contains a single property reference, then the property value | |||
* <code>Object</code> itself is returned. | |||
* Otherwise, a <code>String</code> is returned, comprising the supplied | |||
* content, with all property references replaced with the result of | |||
* <code>toString()</code> called on the property value. | |||
* | |||
* @param content the property to resolve | |||
* @param context the context in which to resolve property | |||
* @return the reolved property | |||
* @exception TaskException if an error occurs | |||
*/ | |||
public Object resolveProperties( final String content, | |||
final TaskContext context ) | |||
throws TaskException | |||
{ | |||
int start = findNextProperty( content, 0 ); | |||
if( -1 == start ) | |||
{ | |||
return content; | |||
} | |||
int end = findEnding( content, start ); | |||
final int length = content.length(); | |||
if( 0 == start && end == ( length - 1 ) ) | |||
{ | |||
return getPropertyValue( content.substring( start + 2, end ), | |||
context ); | |||
} | |||
final StringBuffer sb = new StringBuffer( length * 2 ); | |||
int lastPlace = 0; | |||
while( true ) | |||
{ | |||
final String propertyValue = | |||
getPropertyStringValue( content.substring( start + 2, end ), | |||
context ); | |||
sb.append( content.substring( lastPlace, start ) ); | |||
sb.append( propertyValue ); | |||
lastPlace = end + 1; | |||
start = findNextProperty( content, lastPlace ); | |||
if( -1 == start ) | |||
{ | |||
break; | |||
} | |||
end = findEnding( content, start ); | |||
} | |||
sb.append( content.substring( lastPlace, length ) ); | |||
return sb.toString(); | |||
} | |||
/** | |||
* Resolve a string property. This recursively evaluates all property | |||
* substitutions based on specified context. | |||
* | |||
* @param content the property to resolve | |||
* @param context the context in which to resolve property | |||
* @return the reolved property | |||
* @exception TaskException if an error occurs | |||
*/ | |||
private Object recursiveResolveProperty( final String content, | |||
final TaskContext context ) | |||
throws TaskException | |||
{ | |||
int start = findNextProperty( content, 0 ); | |||
if( -1 == start ) | |||
{ | |||
return content; | |||
} | |||
int end = findNestedEnding( content, start ); | |||
final int length = content.length(); | |||
if( 0 == start && end == ( length - 1 ) ) | |||
{ | |||
final String propertyName = content.substring( start + 2, end ); | |||
final Object key = recursiveResolveProperty( propertyName, context ); | |||
return getPropertyValue( key.toString(), context ); | |||
} | |||
final StringBuffer sb = new StringBuffer( length * 2 ); | |||
int lastPlace = 0; | |||
while( true ) | |||
{ | |||
final String propertyName = content.substring( start + 2, end ); | |||
final Object key = recursiveResolveProperty( propertyName, context ); | |||
final String value = getPropertyStringValue( key.toString(), context ); | |||
sb.append( content.substring( lastPlace, start ) ); | |||
sb.append( value ); | |||
lastPlace = end + 1; | |||
start = findNextProperty( content, lastPlace ); | |||
if( -1 == start ) | |||
{ | |||
break; | |||
} | |||
end = findNestedEnding( content, start ); | |||
} | |||
sb.append( content.substring( lastPlace, length ) ); | |||
return sb.toString(); | |||
} | |||
/** | |||
* Finds the next occurrance of the start of a Property identifier. | |||
* @param content the String to search | |||
* @param currentPosition start location of the search | |||
* @return the position of the next occurrence, or <code>-1</code> if none | |||
* was found. | |||
*/ | |||
private int findNextProperty( final String content, final int currentPosition ) | |||
{ | |||
//TODO: Check if it is commented out | |||
return content.indexOf( "${", currentPosition ); | |||
} | |||
/** | |||
* Finds the next occurrence of the end of a Property identifier. | |||
* @param property the String to search | |||
* @param currentPosition start location of the search | |||
* @return the position of the next occurrence | |||
* @throws TaskException if no end was found | |||
*/ | |||
private int findEnding( final String property, final int currentPosition ) | |||
throws TaskException | |||
{ | |||
//TODO: Check if it is commented out | |||
final int index = property.indexOf( '}', currentPosition ); | |||
if( -1 == index ) | |||
{ | |||
final String message = REZ.getString( "prop.mismatched-braces.error" ); | |||
throw new TaskException( message ); | |||
} | |||
return index; | |||
} | |||
/** | |||
* Finds the end of the property identifier at the currentPosition, | |||
* taking into account nested property identifiers. | |||
* @param property the String to search | |||
* @param currentPosition location of the property | |||
* @return the position of the propery ending. | |||
* @throws TaskException if the property is not properly ended. | |||
*/ | |||
private int findNestedEnding( final String property, final int currentPosition ) | |||
throws TaskException | |||
{ | |||
final int length = property.length(); | |||
final int start = currentPosition + 2; | |||
int weight = 1; | |||
for( int i = start; ( weight > 0 ) && ( i < length ); i++ ) | |||
{ | |||
final char ch = property.charAt( i ); | |||
switch( ch ) | |||
{ | |||
case '}': | |||
//TODO: Check if it is commented out | |||
weight--; | |||
if( weight == 0 ) | |||
{ | |||
return i; | |||
} | |||
break; | |||
case '$': | |||
{ | |||
//TODO: Check if it is commented out | |||
final int next = i + 1; | |||
if( next < length && '{' == property.charAt( next ) ) | |||
{ | |||
weight++; | |||
} | |||
} | |||
break; | |||
} | |||
} | |||
final String message = REZ.getString( "prop.mismatched-braces.error" ); | |||
throw new TaskException( message ); | |||
} | |||
/** | |||
* Returns a property's value, converted to a String. | |||
*/ | |||
private String getPropertyStringValue( final String propertyName, | |||
final TaskContext context ) | |||
throws TaskException | |||
{ | |||
final Object value = getPropertyValue( propertyName, context ); | |||
if( value instanceof String ) | |||
{ | |||
return (String)value; | |||
} | |||
try | |||
{ | |||
return (String)m_converter.convert( String.class, value, context ); | |||
} | |||
catch( final ConverterException e ) | |||
{ | |||
throw new TaskException( e.getMessage(), e ); | |||
} | |||
} | |||
/** | |||
* Retrieve a value from the specified context using the specified key. | |||
* | |||
* @param propertyName the key of value in context | |||
* @param context the set of known properties | |||
* @return the object retrieved from context | |||
* @exception TaskException if the property is undefined | |||
*/ | |||
protected Object getPropertyValue( final String propertyName, | |||
final TaskContext context ) | |||
throws TaskException | |||
{ | |||
final Object value = context.getProperty( propertyName ); | |||
if( value != null ) | |||
{ | |||
return value; | |||
} | |||
final String message = REZ.getString( "prop.missing-value.error", propertyName ); | |||
throw new TaskException( message ); | |||
} | |||
} | |||
@@ -1,3 +0,0 @@ | |||
#AbstractPropertyResolver | |||
prop.mismatched-braces.error=Malformed property with mismatched }'s. | |||
prop.missing-value.error=Unknown property "{0}". |
@@ -1,163 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.role; | |||
import java.util.HashMap; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.myrmidon.interfaces.role.RoleException; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
/** | |||
* Interface to manage roles and mapping to names. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version CVS $Revision$ $Date$ | |||
*/ | |||
public class DefaultRoleManager | |||
implements RoleManager | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultRoleManager.class ); | |||
/** Parent <code>RoleManager</code> for nested resolution */ | |||
private final RoleManager m_parent; | |||
/** Map from shorthand name -> RoleInfo. */ | |||
private final HashMap m_shorthandMap = new HashMap(); | |||
/** Map from role name -> RoleInfo. */ | |||
private final HashMap m_nameMap = new HashMap(); | |||
/** Map from role type -> RoleInfo. */ | |||
private final HashMap m_typeMap = new HashMap(); | |||
/** | |||
* constructor--this RoleManager has no parent. | |||
*/ | |||
public DefaultRoleManager() | |||
{ | |||
this( null ); | |||
} | |||
/** | |||
* Alternate constructor--this RoleManager has the specified | |||
* parent. | |||
* | |||
* @param parent The parent <code>RoleManager</code>. | |||
*/ | |||
public DefaultRoleManager( final RoleManager parent ) | |||
{ | |||
m_parent = parent; | |||
} | |||
/** | |||
* Find role based on shorthand name. | |||
* | |||
* @param name the shorthand name | |||
* @return the role, or null if the role cannot be found. | |||
*/ | |||
public RoleInfo getRoleByShorthandName( final String name ) | |||
{ | |||
final RoleInfo role = (RoleInfo)m_shorthandMap.get( name ); | |||
if( null == role && null != m_parent ) | |||
{ | |||
return m_parent.getRoleByShorthandName( name ); | |||
} | |||
return role; | |||
} | |||
/** | |||
* Find role based on role type. | |||
* | |||
* @param type the role type. | |||
* @return the role, or null if the role cannot be found. | |||
*/ | |||
public RoleInfo getRoleByType( final Class type ) | |||
{ | |||
final RoleInfo role = (RoleInfo)m_typeMap.get( type ); | |||
if( null == role && null != m_parent ) | |||
{ | |||
return m_parent.getRoleByType( type ); | |||
} | |||
return role; | |||
} | |||
/** | |||
* Find role based on name. | |||
* | |||
* @param name the role name | |||
* @return the role, or null if the role cannot be found. | |||
*/ | |||
public RoleInfo getRole( final String name ) | |||
{ | |||
final RoleInfo role = (RoleInfo)m_nameMap.get( name ); | |||
if( null == role && null != m_parent ) | |||
{ | |||
return m_parent.getRole( name ); | |||
} | |||
return role; | |||
} | |||
/** | |||
* Adds a role definition. | |||
*/ | |||
public void addRole( final RoleInfo role ) throws RoleException | |||
{ | |||
// Check for duplicate role names | |||
final String roleName = role.getName(); | |||
RoleInfo oldRole = (RoleInfo)m_nameMap.get( roleName ); | |||
if( null != oldRole && !oldRole.equals( role ) ) | |||
{ | |||
final String message = REZ.getString( "duplicate-role.error", roleName ); | |||
throw new RoleException( message ); | |||
} | |||
// Check for duplicate shorthand names | |||
final String shorthand = role.getShorthand(); | |||
if( shorthand != null ) | |||
{ | |||
oldRole = (RoleInfo)m_shorthandMap.get( shorthand ); | |||
if( null != oldRole && !oldRole.equals( role ) ) | |||
{ | |||
final String message = REZ.getString( "duplicate-shorthand.error", shorthand ); | |||
throw new RoleException( message ); | |||
} | |||
} | |||
// Check for duplicate types | |||
final Class roleType = role.getType(); | |||
if( roleType != null ) | |||
{ | |||
oldRole = (RoleInfo)m_typeMap.get( roleType ); | |||
if( null != oldRole && !oldRole.equals( role ) ) | |||
{ | |||
final String message = REZ.getString( "duplicate-type.error", roleType.getName() ); | |||
throw new RoleException( message ); | |||
} | |||
} | |||
// Add the role to the maps | |||
m_nameMap.put( roleName, role ); | |||
if( shorthand != null ) | |||
{ | |||
m_shorthandMap.put( shorthand, role ); | |||
} | |||
if( roleType != null ) | |||
{ | |||
m_typeMap.put( roleType, role ); | |||
} | |||
} | |||
} |
@@ -1,3 +0,0 @@ | |||
duplicate-shorthand.error=Duplicate roles with shorthand name "{0}". | |||
duplicate-type.error=Duplicate roles with type "{0}". | |||
duplicate-role.error=Duplicate roles with name "{0}". |
@@ -1,248 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.activity.Disposable; | |||
import org.apache.avalon.framework.activity.Initializable; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.parameters.ParameterException; | |||
import org.apache.avalon.framework.parameters.Parameterizable; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.avalon.framework.context.Contextualizable; | |||
import org.apache.avalon.framework.context.Context; | |||
import org.apache.avalon.framework.context.ContextException; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* A service manager implementation, which creates service instances on demand. | |||
* | |||
* <p>This manager creates service instances, using a {@link ServiceFactory}, | |||
* and running the service instances through the service lifecycle: | |||
* <ul> | |||
* <li>log enable | |||
* <li>contextualise | |||
* <li>service | |||
* <li>parameterise | |||
* <li>initialise | |||
* <li>use | |||
* <li>dispose | |||
* </ul> | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class InstantiatingServiceManager | |||
extends AbstractLogEnabled | |||
implements ServiceManager, Contextualizable, Parameterizable, Serviceable, Disposable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( InstantiatingServiceManager.class ); | |||
/** Map from service class -> service object. */ | |||
private Map m_services = new HashMap(); | |||
/** The objects (services and factories) that have been created by this mgr. */ | |||
private List m_objects = new ArrayList(); | |||
/** Other services used by this service manager. */ | |||
private TypeFactory m_typeFactory; | |||
private RoleManager m_roleManager; | |||
private ServiceManager m_serviceManager; | |||
private Parameters m_parameters; | |||
private TypeManager m_typeManager; | |||
private Context m_context; | |||
public void contextualize( final Context context ) throws ContextException | |||
{ | |||
m_context = context; | |||
} | |||
public void parameterize( final Parameters parameters ) throws ParameterException | |||
{ | |||
m_parameters = parameters; | |||
} | |||
/** | |||
* Pass the <code>ServiceManager</code> to the <code>servicable</code>. | |||
* The <code>Servicable</code> implementation should use the specified | |||
* <code>ServiceManager</code> to acquire the components it needs for | |||
* execution. | |||
* | |||
* @param manager The <code>ServiceManager</code> which this | |||
* <code>Servicable</code> uses. | |||
*/ | |||
public void service( final ServiceManager manager ) | |||
throws ServiceException | |||
{ | |||
m_serviceManager = manager; | |||
m_roleManager = (RoleManager)manager.lookup( RoleManager.ROLE ); | |||
m_typeManager = (TypeManager)manager.lookup( TypeManager.ROLE ); | |||
} | |||
/** | |||
* Disposes this service manager, and all services created by it. | |||
*/ | |||
public void dispose() | |||
{ | |||
// Dispose the services | |||
for( Iterator iterator = m_objects.iterator(); iterator.hasNext(); ) | |||
{ | |||
final Object object = iterator.next(); | |||
if( object instanceof Disposable ) | |||
{ | |||
( (Disposable)object ).dispose(); | |||
} | |||
} | |||
// Ditch state | |||
m_services = null; | |||
m_typeFactory = null; | |||
m_objects = null; | |||
m_parameters = null; | |||
m_roleManager = null; | |||
m_serviceManager = null; | |||
} | |||
/** | |||
* Determines if this service manager contains a particular service. | |||
*/ | |||
public boolean hasService( final String serviceRole ) | |||
{ | |||
// If we have already instantiated the service, or if we know how | |||
// to instantiate it, then return true | |||
if( m_services.containsKey( serviceRole ) ) | |||
{ | |||
return true; | |||
} | |||
try | |||
{ | |||
return getFactory().canCreate( serviceRole ); | |||
} | |||
catch( TypeException e ) | |||
{ | |||
// Throw away exception - yuck | |||
} | |||
return false; | |||
} | |||
/** | |||
* Locates the type factory to use to instantiate service factories. | |||
*/ | |||
private TypeFactory getFactory() throws TypeException | |||
{ | |||
if( m_typeFactory == null ) | |||
{ | |||
m_typeFactory = m_typeManager.getFactory( ServiceFactory.ROLE ); | |||
} | |||
return m_typeFactory; | |||
} | |||
/** | |||
* Locates a service instance. | |||
*/ | |||
public Object lookup( final String serviceRole ) | |||
throws ServiceException | |||
{ | |||
Object service = m_services.get( serviceRole ); | |||
if( service == null ) | |||
{ | |||
// Create the service | |||
service = createService( serviceRole ); | |||
m_services.put( serviceRole, service ); | |||
} | |||
return service; | |||
} | |||
/** | |||
* Releases a service. | |||
*/ | |||
public void release( final Object service ) | |||
{ | |||
} | |||
/** | |||
* Creates the service object for a service role. | |||
*/ | |||
private Object createService( final String serviceRole ) throws ServiceException | |||
{ | |||
try | |||
{ | |||
// Create the factory | |||
final ServiceFactory factory = (ServiceFactory)getFactory().create( serviceRole ); | |||
setupObject( factory ); | |||
// Create the service | |||
final Object service = factory.createService(); | |||
// Check the service is assignable to the role type | |||
final RoleInfo roleInfo = m_roleManager.getRole( serviceRole ); | |||
final Class serviceType = roleInfo.getType(); | |||
if( serviceType != null && !serviceType.isInstance( service ) ) | |||
{ | |||
final String message = REZ.getString( "mismatched-service-type.error", | |||
serviceRole, service.getClass().getName() ); | |||
throw new ServiceException( message ); | |||
} | |||
setupObject( service ); | |||
return service; | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "create-service.error", serviceRole ); | |||
throw new ServiceException( message, e ); | |||
} | |||
} | |||
/** | |||
* Sets-up an object, taking it through the lifecycle steps. | |||
*/ | |||
private void setupObject( final Object object ) | |||
throws Exception | |||
{ | |||
setupLogger( object ); | |||
if( m_context != null && object instanceof Contextualizable ) | |||
{ | |||
( (Contextualizable)object ).contextualize( m_context ); | |||
} | |||
if( object instanceof Serviceable ) | |||
{ | |||
( (Serviceable)object ).service( m_serviceManager ); | |||
} | |||
if( m_parameters != null && object instanceof Parameterizable ) | |||
{ | |||
( (Parameterizable)object ).parameterize( m_parameters ); | |||
} | |||
if( object instanceof Initializable ) | |||
{ | |||
( (Initializable)object ).initialize(); | |||
} | |||
m_objects.add( object ); | |||
} | |||
} |
@@ -1,3 +0,0 @@ | |||
unknown-service-type.error=Unknown service "{0}". | |||
mismatched-service-type.error=Service factory for service "{0}" produced an object of unexpected type {1}. | |||
create-service.error=Could not create service "{0}". |
@@ -1,268 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.store; | |||
import java.io.File; | |||
import java.util.HashMap; | |||
import java.util.Hashtable; | |||
import java.util.Map; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.interfaces.model.DefaultNameValidator; | |||
import org.apache.myrmidon.interfaces.model.NameValidator; | |||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||
/** | |||
* This is the Default implementation of PropertyStore. It follows | |||
* the following rules; | |||
* | |||
* <ul> | |||
* <li>The property names must pass DefaultNameValidator checks</li> | |||
* <li>The store is mutable</li> | |||
* <li>If the key is TaskContext.NAME then value must be a string.</li> | |||
* <li>If the key is TaskContext.BASE_DIRECTORY then value must be a key.</li> | |||
* </ul> | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
* @see org.apache.myrmidon.interfaces.property.PropertyStore | |||
*/ | |||
public class DefaultPropertyStore | |||
implements PropertyStore | |||
{ | |||
private final static Resources REZ = | |||
ResourceManager.getPackageResources( DefaultPropertyStore.class ); | |||
/** | |||
* The parent store (may be null). | |||
*/ | |||
private final PropertyStore m_parent; | |||
/** | |||
* The name validator to check property names against. | |||
*/ | |||
private final NameValidator m_validator; | |||
/** | |||
* The underlying map where propertys are actually stored. | |||
*/ | |||
private final Map m_contextData = new Hashtable(); | |||
/** | |||
* Construct a PropertyStore with no parent and | |||
* default name-validator. | |||
*/ | |||
public DefaultPropertyStore() | |||
{ | |||
this( "", null, null ); | |||
} | |||
/** | |||
* Construct a PropertyStore with specified parent. | |||
* | |||
* @param parent the parent PropertyStore (may be null). | |||
* @param validator the validator to use to check property names (may be null). | |||
*/ | |||
public DefaultPropertyStore( final String name, | |||
final PropertyStore parent, | |||
final NameValidator validator ) | |||
{ | |||
m_parent = parent; | |||
NameValidator candidateValidator = validator; | |||
if( null == candidateValidator ) | |||
{ | |||
candidateValidator = createDefaultNameValidator(); | |||
} | |||
m_validator = candidateValidator; | |||
m_contextData.put( TaskContext.NAME, name ); | |||
} | |||
/** | |||
* Set the property with specified name to specified value. | |||
* The specific implementation will apply various rules | |||
* before setting the property. | |||
* | |||
* @param name the name of property | |||
* @param value the value of property | |||
* @throws TaskException if property can not be set | |||
*/ | |||
public void setProperty( final String name, final Object value ) | |||
throws TaskException | |||
{ | |||
checkPropertyName( name ); | |||
checkPropertyValid( name, value ); | |||
if ( value == null ) | |||
{ | |||
m_contextData.remove( name ); | |||
} | |||
else | |||
{ | |||
m_contextData.put( name, value ); | |||
} | |||
} | |||
/** | |||
* Return <code>true</code> if the specified property is set. | |||
* | |||
* @param name the name of property | |||
*/ | |||
public boolean isPropertySet( final String name ) | |||
{ | |||
try | |||
{ | |||
getProperty( name ); | |||
return true; | |||
} | |||
catch( Exception e ) | |||
{ | |||
} | |||
return false; | |||
} | |||
/** | |||
* Retrieve the value of specified property. | |||
* Will return null if no such property exists. | |||
* | |||
* @param name the name of the property | |||
* @return the value of the property, or null if no such property | |||
* @throws TaskException if theres an error retrieving property, such | |||
* as an invalid property name | |||
*/ | |||
public Object getProperty( final String name ) | |||
throws TaskException | |||
{ | |||
Object value = m_contextData.get( name ); | |||
if( value != null ) | |||
{ | |||
return value; | |||
} | |||
if( m_parent != null ) | |||
{ | |||
return m_parent.getProperty( name ); | |||
} | |||
final String message = REZ.getString( "unknown-prop.error", name ); | |||
throw new TaskException( message ); | |||
} | |||
/** | |||
* Retrieve a copy of all the properties that are "in-scope" | |||
* for store. | |||
* | |||
* @return a copy of all the properties that are "in-scope" | |||
* for store. | |||
* @throws TaskException if theres an error retrieving propertys | |||
*/ | |||
public Map getProperties() | |||
throws TaskException | |||
{ | |||
final Map properties = new HashMap(); | |||
if( m_parent != null ) | |||
{ | |||
properties.putAll( m_parent.getProperties() ); | |||
} | |||
properties.putAll( m_contextData ); | |||
return properties; | |||
} | |||
/** | |||
* Return a child PropertyStore with specified name. | |||
* This is to allow support for scoped stores. However a | |||
* store may choose to be unscoped and just return a | |||
* reference to itself. | |||
* | |||
* @param name the name of child store | |||
* @return the child store | |||
* @throws TaskException if theres an error creating child store | |||
*/ | |||
public PropertyStore createChildStore( final String name ) | |||
throws TaskException | |||
{ | |||
// Build the name for the new store | |||
final String thisName = (String)m_contextData.get( TaskContext.NAME ); | |||
final String newName; | |||
if( name == null || name.length() == 0 ) | |||
{ | |||
newName = thisName; | |||
} | |||
else if( thisName.length() == 0 ) | |||
{ | |||
newName = name; | |||
} | |||
else | |||
{ | |||
newName = thisName + "." + name; | |||
} | |||
return new DefaultPropertyStore( newName, this, m_validator ); | |||
} | |||
/** | |||
* Checks that the supplied property name is valid. | |||
*/ | |||
private void checkPropertyName( final String name ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
m_validator.validate( name ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
String message = REZ.getString( "bad-property-name.error", name ); | |||
throw new TaskException( message, e ); | |||
} | |||
} | |||
/** | |||
* Make sure property is valid if it is one of the "magic" properties. | |||
* | |||
* @param name the name of property | |||
* @param value the value of proeprty | |||
* @exception TaskException if an error occurs | |||
*/ | |||
private void checkPropertyValid( final String name, final Object value ) | |||
throws TaskException | |||
{ | |||
if( TaskContext.BASE_DIRECTORY.equals( name ) && !( value instanceof File ) ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-property.error", | |||
TaskContext.BASE_DIRECTORY, | |||
File.class.getName() ); | |||
throw new TaskException( message ); | |||
} | |||
else if( TaskContext.NAME.equals( name ) && !( value instanceof String ) ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-property.error", | |||
TaskContext.NAME, | |||
String.class.getName() ); | |||
throw new TaskException( message ); | |||
} | |||
} | |||
/** | |||
* Create an instance of the default the name validator. | |||
* | |||
* @return the default NameValidator | |||
*/ | |||
private static NameValidator createDefaultNameValidator() | |||
{ | |||
final DefaultNameValidator defaultValidator = new DefaultNameValidator(); | |||
defaultValidator.setAllowInternalWhitespace( false ); | |||
defaultValidator.setAdditionalInternalCharacters( "_-.+" ); | |||
return defaultValidator; | |||
} | |||
} |
@@ -1,5 +0,0 @@ | |||
unknown-prop.error=Unknown property "{0}". | |||
bad-property.error=Property "{0}" must have a value of type {1}. | |||
bad-property-name.error=Invalid property name "{0}". | |||
null-resolved-value.error=Value "{0}" resolved to null. | |||
bad-resolve.error=Unable to resolve value "{0}". |
@@ -1,139 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.type; | |||
import java.util.HashMap; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.type.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* The interface that is used to manage types. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultTypeManager | |||
implements TypeManager, Serviceable | |||
{ | |||
private static final Resources REZ | |||
= ResourceManager.getPackageResources( DefaultTypeManager.class ); | |||
///Parent type manager to inherit values from. | |||
private final DefaultTypeManager m_parent; | |||
///Maps role Class to MultiSourceTypeFactory. | |||
private final HashMap m_roleMap = new HashMap(); | |||
private RoleManager m_roleManager; | |||
public DefaultTypeManager() | |||
{ | |||
this( null ); | |||
} | |||
private DefaultTypeManager( final DefaultTypeManager parent ) | |||
{ | |||
m_parent = parent; | |||
if( m_parent != null ) | |||
{ | |||
m_roleManager = m_parent.m_roleManager; | |||
} | |||
} | |||
public void service( final ServiceManager serviceManager ) | |||
throws ServiceException | |||
{ | |||
m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||
} | |||
public void registerType( final String roleName, | |||
final String shorthandName, | |||
final TypeFactory factory ) | |||
throws TypeException | |||
{ | |||
final MultiSourceTypeFactory msFactory = createFactory( roleName ); | |||
msFactory.register( shorthandName, factory ); | |||
} | |||
public TypeFactory getFactory( final String roleName ) | |||
throws TypeException | |||
{ | |||
return createFactory( roleName ); | |||
} | |||
public TypeManager createChildTypeManager() | |||
{ | |||
return new DefaultTypeManager( this ); | |||
} | |||
private final MultiSourceTypeFactory lookupFactory( final String roleName ) | |||
{ | |||
return (MultiSourceTypeFactory)m_roleMap.get( roleName ); | |||
} | |||
/** | |||
* Get a factory of appropriate role. | |||
* Create a Factory if none exists with same name. | |||
* | |||
* @param roleName the role name | |||
* @return the Factory for interface | |||
* @exception TypeException role does not specify accessible work interface | |||
*/ | |||
private MultiSourceTypeFactory createFactory( final String roleName ) | |||
throws TypeException | |||
{ | |||
MultiSourceTypeFactory factory = (MultiSourceTypeFactory)m_roleMap.get( roleName ); | |||
if( null != factory ) | |||
{ | |||
return factory; | |||
} | |||
final MultiSourceTypeFactory parentFactory = getParentTypedFactory( roleName ); | |||
if( null != parentFactory ) | |||
{ | |||
factory = new MultiSourceTypeFactory( parentFactory ); | |||
} | |||
///If we haven't got factory try to create a new one | |||
if( null == factory ) | |||
{ | |||
// Lookup the role type | |||
final RoleInfo role = m_roleManager.getRole( roleName ); | |||
if( role == null ) | |||
{ | |||
final String message = REZ.getString( "unknown-role.error", roleName ); | |||
throw new TypeException( message ); | |||
} | |||
factory = new MultiSourceTypeFactory( role.getType() ); | |||
} | |||
m_roleMap.put( roleName, factory ); | |||
return factory; | |||
} | |||
private MultiSourceTypeFactory getParentTypedFactory( final String roleName ) | |||
{ | |||
if( null != m_parent ) | |||
{ | |||
return m_parent.lookupFactory( roleName ); | |||
} | |||
else | |||
{ | |||
return null; | |||
} | |||
} | |||
} |
@@ -1,124 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.type; | |||
import java.util.HashMap; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.myrmidon.interfaces.type.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
/** | |||
* This factory acts as a proxy to set of object factories. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class MultiSourceTypeFactory | |||
implements TypeFactory | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( MultiSourceTypeFactory.class ); | |||
///Parent Selector | |||
private final MultiSourceTypeFactory m_parent; | |||
///Map of name->factory list | |||
private final HashMap m_factories = new HashMap(); | |||
///Type expected to be created from factories | |||
private final Class m_type; | |||
public MultiSourceTypeFactory( final Class type ) | |||
{ | |||
m_type = type; | |||
m_parent = null; | |||
} | |||
public MultiSourceTypeFactory( final MultiSourceTypeFactory parent ) | |||
{ | |||
m_type = parent.getType(); | |||
m_parent = parent; | |||
} | |||
/** | |||
* Populate the ComponentSelector. | |||
*/ | |||
public void register( final String name, final TypeFactory factory ) | |||
{ | |||
m_factories.put( name, factory ); | |||
} | |||
/** | |||
* Determines if this factory can create instances of a particular type. | |||
*/ | |||
public boolean canCreate( final String name ) | |||
{ | |||
return ( findFactory( name ) != null ); | |||
} | |||
/** | |||
* Create a type instance based on name. | |||
* | |||
* @param name the name | |||
* @return the type instance | |||
* @exception TypeException if an error occurs | |||
*/ | |||
public Object create( final String name ) | |||
throws TypeException | |||
{ | |||
// Locate the factory to use | |||
TypeFactory factory = findFactory( name ); | |||
if( null == factory ) | |||
{ | |||
final String message = REZ.getString( "no-factory.error", name ); | |||
throw new TypeException( message ); | |||
} | |||
// Create the object | |||
final Object object = factory.create( name ); | |||
if( m_type != null && !m_type.isInstance( object ) ) | |||
{ | |||
final String message = REZ.getString( "mismatched-type.error", | |||
name, object.getClass().getName() ); | |||
throw new TypeException( message ); | |||
} | |||
return object; | |||
} | |||
/** | |||
* Locates the type factory to use for a particular type. | |||
*/ | |||
private TypeFactory findFactory( final String name ) | |||
{ | |||
TypeFactory factory = getTypeFactory( name ); | |||
if( null == factory && null != m_parent ) | |||
{ | |||
factory = m_parent.getTypeFactory( name ); | |||
} | |||
return factory; | |||
} | |||
/** | |||
* Retrieve type managed by selector. | |||
* Used by other instances of TypedComponentSelector. | |||
* | |||
* @return the type class | |||
*/ | |||
private final Class getType() | |||
{ | |||
return m_type; | |||
} | |||
private final TypeFactory getTypeFactory( final String name ) | |||
{ | |||
return (TypeFactory)m_factories.get( name ); | |||
} | |||
} |
@@ -1,9 +0,0 @@ | |||
# DefaultTypeManager | |||
unknown-role.error=Cannot create a type factory for unknown role {0}. | |||
# MultiSourceTypeFactory | |||
no-instantiate.error=Unable to instantiate ({0}). | |||
no-mapping.error=Malconfigured factory, no classname for ({0}). | |||
no-factory.error=Failed to locate factory for {0}. | |||
mismatched-type.error=Factory for type {0} created an object of incompatible type {1}. | |||
no-work-interface.error=Role {0} does not specify accessible work interface. |
@@ -1,61 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.workspace; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||
/** | |||
* Frames in which tasks are executed. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultExecutionFrame | |||
implements ExecutionFrame | |||
{ | |||
private final Logger m_logger; | |||
private final PropertyStore m_propertyStore; | |||
private final ServiceManager m_serviceManager; | |||
public DefaultExecutionFrame( final Logger logger, | |||
final PropertyStore propertyStore, | |||
final ServiceManager serviceManager ) | |||
{ | |||
m_logger = logger; | |||
m_propertyStore = propertyStore; | |||
m_serviceManager = serviceManager; | |||
} | |||
/** | |||
* Returns the logger which is to be supplied to tasks. | |||
*/ | |||
public Logger getLogger() | |||
{ | |||
return m_logger; | |||
} | |||
/** | |||
* Returns the set of services to use to create, configure, and execute | |||
* tasks. | |||
*/ | |||
public ServiceManager getServiceManager() | |||
{ | |||
return m_serviceManager; | |||
} | |||
/** | |||
* Returns the set of properties to be supplied to tasks. | |||
*/ | |||
public PropertyStore getProperties() | |||
{ | |||
return m_propertyStore; | |||
} | |||
} |
@@ -1,382 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.workspace; | |||
import java.io.File; | |||
import java.util.Map; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.excalibur.io.FileUtil; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||
/** | |||
* Default implementation of TaskContext. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultTaskContext | |||
implements TaskContext | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultTaskContext.class ); | |||
private final ServiceManager m_serviceManager; | |||
private final Logger m_logger; | |||
private final PropertyStore m_store; | |||
private PropertyResolver m_propertyResolver; | |||
/** | |||
* Constructor that takes both parent context and a service directory. | |||
*/ | |||
public DefaultTaskContext( final ServiceManager serviceManager, | |||
final Logger logger, | |||
final PropertyStore store ) | |||
{ | |||
m_serviceManager = serviceManager; | |||
m_logger = logger; | |||
m_store = store; | |||
if( null == m_serviceManager ) | |||
{ | |||
throw new NullPointerException( "serviceManager" ); | |||
} | |||
if( null == m_logger ) | |||
{ | |||
throw new NullPointerException( "logger" ); | |||
} | |||
if( null == m_store ) | |||
{ | |||
throw new NullPointerException( "store" ); | |||
} | |||
} | |||
/** | |||
* Retrieve Name of task. | |||
* | |||
* @return the name | |||
*/ | |||
public String getName() | |||
{ | |||
return (String)getProperty( NAME ); | |||
} | |||
/** | |||
* Retrieve base directory. | |||
* | |||
* @return the base directory | |||
*/ | |||
public File getBaseDirectory() | |||
{ | |||
return (File)getProperty( BASE_DIRECTORY ); | |||
} | |||
/** | |||
* Retrieve a service that is offered by the runtime. | |||
* The actual services registered and in place for the | |||
* task is determined by the container. The returned service | |||
* <b>MUST</b> implement the specified interface. | |||
* | |||
* @param serviceClass the interface class that defines the service | |||
* @return an instance of the service implementing interface specified by parameter | |||
* @exception TaskException is thrown when the service is unavailable or not supported | |||
*/ | |||
public Object getService( final Class serviceClass ) | |||
throws TaskException | |||
{ | |||
final String name = serviceClass.getName(); | |||
//Note that this will chain up to parent ServiceManagers (if any) | |||
if( null != m_serviceManager && m_serviceManager.hasService( name ) ) | |||
{ | |||
try | |||
{ | |||
return m_serviceManager.lookup( name ); | |||
} | |||
catch( final ServiceException se ) | |||
{ | |||
throw new TaskException( se.getMessage(), se ); | |||
} | |||
} | |||
// Not found | |||
final String message = REZ.getString( "bad-find-service.error", name ); | |||
throw new TaskException( message ); | |||
} | |||
/** | |||
* Resolve filename. | |||
* This involves resolving it against baseDirectory and | |||
* removing ../ and ./ references. It also means formatting | |||
* it appropriately for the particular OS (ie different OS have | |||
* different volumes, file conventions etc) | |||
* | |||
* @param filename the filename to resolve | |||
* @return the resolved filename | |||
*/ | |||
public File resolveFile( final String filename ) | |||
{ | |||
return FileUtil.resolveFile( getBaseDirectory(), filename ); | |||
} | |||
/** | |||
* Resolve a value according to the context. | |||
* This involves evaluating the string and thus removing | |||
* ${} sequences according to the rules specified at | |||
* ............ | |||
* | |||
* @param value the value to resolve | |||
* @return the resolved value | |||
*/ | |||
public Object resolveValue( final String value ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
if( null == m_propertyResolver ) | |||
{ | |||
m_propertyResolver = (PropertyResolver)getService( PropertyResolver.class ); | |||
} | |||
final Object object = | |||
m_propertyResolver.resolveProperties( value, this ); | |||
if( null == object ) | |||
{ | |||
final String message = REZ.getString( "null-resolved-value.error", value ); | |||
throw new TaskException( message ); | |||
} | |||
return object; | |||
} | |||
catch( final TaskException te ) | |||
{ | |||
final String message = REZ.getString( "bad-resolve.error", value ); | |||
throw new TaskException( message, te ); | |||
} | |||
} | |||
/** | |||
* Retrieve property for name. | |||
* | |||
* @param name the name of property | |||
* @return the value of the property | |||
*/ | |||
public Object getProperty( final String name ) | |||
{ | |||
try | |||
{ | |||
return m_store.getProperty( name ); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
return null; | |||
} | |||
} | |||
/** | |||
* Retrieve a copy of all the properties accessible via context. | |||
* | |||
* @return the map of all property names to values | |||
*/ | |||
public Map getProperties() | |||
throws TaskException | |||
{ | |||
return m_store.getProperties(); | |||
} | |||
/** | |||
* Set property value in current context. | |||
* | |||
* @param name the name of property | |||
* @param value the value of property | |||
*/ | |||
public void setProperty( final String name, final Object value ) | |||
throws TaskException | |||
{ | |||
m_store.setProperty( name, value ); | |||
} | |||
/** | |||
* Log a debug message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void debug( final String message ) | |||
{ | |||
m_logger.debug( message ); | |||
} | |||
/** | |||
* Log a debug message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void debug( final String message, final Throwable throwable ) | |||
{ | |||
m_logger.debug( message, throwable ); | |||
} | |||
/** | |||
* Determine if messages of priority "debug" will be logged. | |||
* | |||
* @return true if "debug" messages will be logged | |||
*/ | |||
public boolean isDebugEnabled() | |||
{ | |||
return m_logger.isDebugEnabled(); | |||
} | |||
/** | |||
* Log a verbose message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void verbose( String message ) | |||
{ | |||
m_logger.info( message ); | |||
} | |||
/** | |||
* Log a verbose message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void verbose( String message, Throwable throwable ) | |||
{ | |||
m_logger.info( message, throwable ); | |||
} | |||
/** | |||
* Determine if messages of priority "verbose" will be logged. | |||
* | |||
* @return true if "verbose" messages will be logged | |||
*/ | |||
public boolean isVerboseEnabled() | |||
{ | |||
return m_logger.isInfoEnabled(); | |||
} | |||
/** | |||
* Log a info message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void info( final String message ) | |||
{ | |||
m_logger.warn( message ); | |||
} | |||
/** | |||
* Log a info message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void info( final String message, final Throwable throwable ) | |||
{ | |||
m_logger.warn( message, throwable ); | |||
} | |||
/** | |||
* Determine if messages of priority "info" will be logged. | |||
* | |||
* @return true if "info" messages will be logged | |||
*/ | |||
public boolean isInfoEnabled() | |||
{ | |||
return m_logger.isWarnEnabled(); | |||
} | |||
/** | |||
* Log a warn message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void warn( final String message ) | |||
{ | |||
m_logger.error( message ); | |||
} | |||
/** | |||
* Log a warn message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void warn( final String message, final Throwable throwable ) | |||
{ | |||
m_logger.error( message, throwable ); | |||
} | |||
/** | |||
* Determine if messages of priority "warn" will be logged. | |||
* | |||
* @return true if "warn" messages will be logged | |||
*/ | |||
public boolean isWarnEnabled() | |||
{ | |||
return m_logger.isErrorEnabled(); | |||
} | |||
/** | |||
* Log a error message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void error( final String message ) | |||
{ | |||
m_logger.fatalError( message ); | |||
} | |||
/** | |||
* Log a error message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void error( final String message, final Throwable throwable ) | |||
{ | |||
m_logger.fatalError( message, throwable ); | |||
} | |||
/** | |||
* Determine if messages of priority "error" will be logged. | |||
* | |||
* @return true if "error" messages will be logged | |||
*/ | |||
public boolean isErrorEnabled() | |||
{ | |||
return m_logger.isFatalErrorEnabled(); | |||
} | |||
/** | |||
* Create a Child Context. | |||
* This allows separate hierarchly contexts to be easily constructed. | |||
* | |||
* @param name the name of sub-context | |||
* @return the created TaskContext | |||
* @exception TaskException if an error occurs | |||
*/ | |||
public TaskContext createSubContext( final String name ) | |||
throws TaskException | |||
{ | |||
final PropertyStore store = m_store.createChildStore( name ); | |||
final DefaultServiceManager serviceManager = | |||
new DefaultServiceManager( m_serviceManager ); | |||
final Logger logger = m_logger.getChildLogger( name ); | |||
return new DefaultTaskContext( serviceManager, logger, store ); | |||
} | |||
} |
@@ -1,437 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.workspace; | |||
import java.io.File; | |||
import java.util.HashMap; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.context.Context; | |||
import org.apache.avalon.framework.context.ContextException; | |||
import org.apache.avalon.framework.context.Contextualizable; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.interfaces.deployer.Deployer; | |||
import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||
import org.apache.myrmidon.interfaces.executor.ExecutionContainer; | |||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||
import org.apache.myrmidon.interfaces.executor.Executor; | |||
import org.apache.myrmidon.interfaces.model.Dependency; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.model.Target; | |||
import org.apache.myrmidon.interfaces.model.TypeLib; | |||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||
import org.apache.myrmidon.listeners.ProjectListener; | |||
/** | |||
* This is the default implementation of Workspace. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultWorkspace | |||
extends AbstractLogEnabled | |||
implements Workspace, ExecutionContainer, Contextualizable | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultWorkspace.class ); | |||
private Executor m_executor; | |||
private ProjectListenerSupport m_listenerSupport = new ProjectListenerSupport(); | |||
private ServiceManager m_serviceManager; | |||
private PropertyStore m_baseStore; | |||
private TypeManager m_typeManager; | |||
private Deployer m_deployer; | |||
private Context m_context; | |||
/** A map from Project object -> ProjectEntry for that project. */ | |||
private HashMap m_entries = new HashMap(); | |||
/** | |||
* Add a listener to project events. | |||
* | |||
* @param listener the listener | |||
*/ | |||
public void addProjectListener( final ProjectListener listener ) | |||
{ | |||
m_listenerSupport.addProjectListener( listener ); | |||
} | |||
/** | |||
* Remove a listener from project events. | |||
* | |||
* @param listener the listener | |||
*/ | |||
public void removeProjectListener( final ProjectListener listener ) | |||
{ | |||
m_listenerSupport.removeProjectListener( listener ); | |||
} | |||
/** | |||
* Sets the root execution frame. | |||
*/ | |||
public void setRootExecutionFrame( final ExecutionFrame frame ) throws Exception | |||
{ | |||
m_baseStore = frame.getProperties(); | |||
m_serviceManager = frame.getServiceManager(); | |||
m_typeManager = (TypeManager)m_serviceManager.lookup( TypeManager.ROLE ); | |||
m_executor = (Executor)m_serviceManager.lookup( Executor.ROLE ); | |||
m_deployer = (Deployer)m_serviceManager.lookup( Deployer.ROLE ); | |||
} | |||
public void contextualize( final Context context ) throws ContextException | |||
{ | |||
m_context = context; | |||
} | |||
/** | |||
* Execute a target in a particular project. | |||
* Execute in the project context. | |||
* | |||
* @param project the Project | |||
* @param target the name of the target | |||
* @exception TaskException if an error occurs | |||
*/ | |||
public void executeProject( final Project project, final String target ) | |||
throws TaskException | |||
{ | |||
final ProjectEntry entry = getProjectEntry( project ); | |||
m_listenerSupport.projectStarted( project.getProjectName() ); | |||
executeTarget( entry, target ); | |||
m_listenerSupport.projectFinished( project.getProjectName() ); | |||
} | |||
private File findTypeLib( final String libraryName ) | |||
throws Exception | |||
{ | |||
//TODO: In future this will be expanded to allow | |||
//users to specify search path or automagically | |||
//add entries to lib path (like user specific or | |||
//workspace specific) | |||
final String name = libraryName.replace( '/', File.separatorChar ) + ".atl"; | |||
final File[] extPath = (File[])m_context.get( "myrmidon.antlib.path" ); | |||
for( int i = 0; i < extPath.length; i++ ) | |||
{ | |||
final File extDir = extPath[ i ]; | |||
final File library = new File( extDir, name ); | |||
if( library.exists() ) | |||
{ | |||
if( !library.canRead() ) | |||
{ | |||
final String message = REZ.getString( "no-read.error", library ); | |||
throw new TaskException( message ); | |||
} | |||
else | |||
{ | |||
return library; | |||
} | |||
} | |||
} | |||
final String message = REZ.getString( "no-library.error", libraryName ); | |||
throw new TaskException( message ); | |||
} | |||
private void deployTypeLib( final Deployer deployer, final Project project ) | |||
throws Exception | |||
{ | |||
final TypeLib[] typeLibs = project.getTypeLibs(); | |||
for( int i = 0; i < typeLibs.length; i++ ) | |||
{ | |||
final TypeLib typeLib = typeLibs[ i ]; | |||
final File file = findTypeLib( typeLib.getLibrary() ); | |||
try | |||
{ | |||
final TypeDeployer typeDeployer = deployer.createDeployer( file ); | |||
if( null == typeLib.getRole() ) | |||
{ | |||
// Deploy everything in the typelib | |||
typeDeployer.deployAll(); | |||
} | |||
else | |||
{ | |||
// Deploy the specified type | |||
typeDeployer.deployType( typeLib.getRole(), typeLib.getName() ); | |||
} | |||
} | |||
catch( final DeploymentException de ) | |||
{ | |||
final String message = REZ.getString( "no-deploy.error", | |||
typeLib.getLibrary(), file ); | |||
throw new TaskException( message, de ); | |||
} | |||
} | |||
} | |||
/** | |||
* Creates an execution frame for a project. | |||
*/ | |||
private ExecutionFrame createExecutionFrame( final Project project ) | |||
throws Exception | |||
{ | |||
//Create per frame ComponentManager | |||
final DefaultServiceManager serviceManager = | |||
new DefaultServiceManager( m_serviceManager ); | |||
//Add in child type manager so each frame can register different | |||
//sets of tasks etc | |||
final TypeManager typeManager = m_typeManager.createChildTypeManager(); | |||
serviceManager.put( TypeManager.ROLE, typeManager ); | |||
// TODO - Add child role manager and configurer | |||
//We need to create a new deployer so that it deploys | |||
//to project specific TypeManager | |||
final Deployer deployer = m_deployer.createChildDeployer( serviceManager ); | |||
serviceManager.put( Deployer.ROLE, deployer ); | |||
// Deploy the imported typelibs | |||
deployTypeLib( deployer, project ); | |||
//We need to place projects and ProjectManager | |||
//in ComponentManager so as to support project-local call() | |||
// TODO - add project to properties, not services | |||
serviceManager.put( Workspace.ROLE, this ); | |||
serviceManager.put( Project.ROLE, project ); | |||
// Create a logger | |||
final Logger logger = | |||
new RoutingLogger( getLogger(), m_listenerSupport ); | |||
// Properties | |||
final PropertyStore store = m_baseStore.createChildStore(""); | |||
store.setProperty( TaskContext.BASE_DIRECTORY, project.getBaseDirectory() ); | |||
final DefaultExecutionFrame frame = | |||
new DefaultExecutionFrame( logger, store, serviceManager ); | |||
/** | |||
* @todo Should no occur but done for the time being to simplify evolution. | |||
*/ | |||
serviceManager.put( ExecutionFrame.ROLE, frame ); | |||
return frame; | |||
} | |||
private ProjectEntry getProjectEntry( final Project project ) | |||
throws TaskException | |||
{ | |||
ProjectEntry entry = (ProjectEntry)m_entries.get( project ); | |||
if( null == entry ) | |||
{ | |||
try | |||
{ | |||
final ExecutionFrame frame = createExecutionFrame( project ); | |||
entry = new ProjectEntry( project, frame ); | |||
m_entries.put( project, entry ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
final String message = REZ.getString( "bad-frame.error" ); | |||
throw new TaskException( message, e ); | |||
} | |||
} | |||
return entry; | |||
} | |||
private Project getProject( final String name, final Project project ) | |||
throws TaskException | |||
{ | |||
final Project other = project.getProject( name ); | |||
if( null == other ) | |||
{ | |||
//TODO: Fix this so location information included in description | |||
final String message = REZ.getString( "no-project.error", name ); | |||
throw new TaskException( message ); | |||
} | |||
return other; | |||
} | |||
/** | |||
* Helper method to execute a target. | |||
* | |||
* @param entry the project to execute | |||
* @param targetName the name of the target to execute | |||
* @exception TaskException if an error occurs | |||
*/ | |||
private void executeTarget( final ProjectEntry entry, | |||
final String targetName ) | |||
throws TaskException | |||
{ | |||
// Locate the target | |||
final Target target = entry.getProject().getTarget( targetName ); | |||
if( null == target ) | |||
{ | |||
final String message = REZ.getString( "no-target.error", targetName ); | |||
throw new TaskException( message ); | |||
} | |||
executeTarget( entry, targetName, target ); | |||
} | |||
/** | |||
* Executes a target. Does not execute the target if it has already been | |||
* executed. Executes the dependencies of the target, before executing | |||
* the target itself. | |||
* | |||
* @param name the name of target | |||
* @param target the target | |||
* @param entry the project in which to execute | |||
* @exception TaskException if an error occurs | |||
*/ | |||
private void executeTarget( final ProjectEntry entry, | |||
final String name, | |||
final Target target ) | |||
throws TaskException | |||
{ | |||
final Project project = entry.getProject(); | |||
// Check target state, to see if it has already been executed, and | |||
// to check for dependency cycles | |||
final TargetState state = entry.getTargetState( target ); | |||
if( state == TargetState.FINISHED ) | |||
{ | |||
// Target has been executed | |||
return; | |||
} | |||
if( state == TargetState.TRAVERSING ) | |||
{ | |||
// Cycle in target dependencies | |||
final String message = REZ.getString( "target-dependency-cycle.error", name ); | |||
throw new TaskException( message ); | |||
} | |||
// Set state to indicate this target has been started | |||
entry.setTargetState( target, TargetState.TRAVERSING ); | |||
// Execute the target's dependencies | |||
// Implicit target first | |||
if( target != project.getImplicitTarget() ) | |||
{ | |||
executeTarget( entry, "<init>", project.getImplicitTarget() ); | |||
} | |||
// Named dependencies | |||
final Dependency[] dependencies = target.getDependencies(); | |||
for( int i = 0; i < dependencies.length; i++ ) | |||
{ | |||
final Dependency dependency = dependencies[ i ]; | |||
final String otherProjectName = dependency.getProjectName(); | |||
if( otherProjectName != null ) | |||
{ | |||
// Dependency in a referenced project | |||
final Project otherProject = getProject( otherProjectName, project ); | |||
final ProjectEntry otherEntry = getProjectEntry( otherProject ); | |||
executeTarget( otherEntry, dependency.getTargetName() ); | |||
} | |||
else | |||
{ | |||
// Dependency in this project | |||
executeTarget( entry, dependency.getTargetName() ); | |||
} | |||
} | |||
// Now execute the target itself | |||
executeTargetNoDeps( entry, name, target ); | |||
// Mark target as complete | |||
entry.setTargetState( target, TargetState.FINISHED ); | |||
} | |||
/** | |||
* Executes a target. Does not check whether the target has been | |||
* executed already, and does not check that its dependencies have been | |||
* executed. | |||
* | |||
* @param entry the project to execute the target in. | |||
* @param name the name of the target. | |||
* @param target the target itself | |||
*/ | |||
private void executeTargetNoDeps( final ProjectEntry entry, | |||
final String name, | |||
final Target target ) | |||
throws TaskException | |||
{ | |||
final Project project = entry.getProject(); | |||
// Notify listeners | |||
m_listenerSupport.targetStarted( project.getProjectName(), name ); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = REZ.getString( "exec-target.notice", | |||
project.getProjectName(), name ); | |||
getLogger().debug( message ); | |||
} | |||
//TODO - put this back in | |||
//frame.getContext().setProperty( Project.TARGET, target ); | |||
// Execute all tasks assciated with target | |||
final Configuration[] tasks = target.getTasks(); | |||
for( int i = 0; i < tasks.length; i++ ) | |||
{ | |||
executeTask( tasks[ i ], entry.getFrame() ); | |||
} | |||
// Notify listeners | |||
m_listenerSupport.targetFinished(); | |||
} | |||
/** | |||
* Execute a task. | |||
* | |||
* @param task the task definition | |||
* @param frame the frame to execute in | |||
* @exception TaskException if an error occurs | |||
*/ | |||
private void executeTask( final Configuration task, final ExecutionFrame frame ) | |||
throws TaskException | |||
{ | |||
final String name = task.getName(); | |||
if( getLogger().isDebugEnabled() ) | |||
{ | |||
final String message = REZ.getString( "exec-task.notice", name ); | |||
getLogger().debug( message ); | |||
} | |||
//is setting name even necessary ??? | |||
frame.getProperties().setProperty( TaskContext.NAME, name ); | |||
//notify listeners | |||
m_listenerSupport.taskStarted( name ); | |||
//run task | |||
m_executor.execute( task, frame ); | |||
//notify listeners task has ended | |||
m_listenerSupport.taskFinished(); | |||
} | |||
} |
@@ -1,62 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.workspace; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.model.Target; | |||
/** | |||
* This contains details for each project that is being executed by a | |||
* DefaultWorkspace. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
final class ProjectEntry | |||
{ | |||
private final Project m_project; | |||
private final ExecutionFrame m_frame; | |||
/** Map from Target -> TargetState for that target. */ | |||
private final Map m_targetState = new HashMap(); | |||
public ProjectEntry( final Project project, | |||
final ExecutionFrame frame ) | |||
{ | |||
m_project = project; | |||
m_frame = frame; | |||
} | |||
public Project getProject() | |||
{ | |||
return m_project; | |||
} | |||
public ExecutionFrame getFrame() | |||
{ | |||
return m_frame; | |||
} | |||
public TargetState getTargetState( final Target target ) | |||
{ | |||
TargetState state = (TargetState)m_targetState.get( target ); | |||
if( state == null ) | |||
{ | |||
state = TargetState.NOT_STARTED; | |||
} | |||
return state; | |||
} | |||
public void setTargetState( final Target target, final TargetState state ) | |||
{ | |||
m_targetState.put( target, state ); | |||
} | |||
} |
@@ -1,224 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.workspace; | |||
import org.apache.myrmidon.listeners.LogEvent; | |||
import org.apache.myrmidon.listeners.ProjectListener; | |||
/** | |||
* Support for the project listener event dispatching. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class ProjectListenerSupport | |||
implements LogEvent | |||
{ | |||
private ProjectListener[] m_listeners = new ProjectListener[ 0 ]; | |||
private String m_projectName; | |||
private String m_targetName; | |||
private String m_taskName; | |||
private String m_message; | |||
private Throwable m_throwable; | |||
/** | |||
* Add an extra project listener that wants to receive notification of listener events. | |||
* | |||
* @param listener the listener | |||
*/ | |||
public void addProjectListener( final ProjectListener listener ) | |||
{ | |||
final ProjectListener[] listeners = new ProjectListener[ m_listeners.length + 1 ]; | |||
System.arraycopy( m_listeners, 0, listeners, 0, m_listeners.length ); | |||
listeners[ m_listeners.length ] = listener; | |||
m_listeners = listeners; | |||
} | |||
/** | |||
* Remove a project listener that wants to receive notification of listener events. | |||
* | |||
* @param listener the listener | |||
*/ | |||
public void removeProjectListener( final ProjectListener listener ) | |||
{ | |||
int found = -1; | |||
for( int i = 0; i < m_listeners.length; i++ ) | |||
{ | |||
if( listener == m_listeners[ i ] ) | |||
{ | |||
found = i; | |||
break; | |||
} | |||
} | |||
if( -1 == found ) | |||
{ | |||
return; | |||
} | |||
final ProjectListener[] listeners = new ProjectListener[ m_listeners.length - 1 ]; | |||
System.arraycopy( m_listeners, 0, listeners, 0, found ); | |||
final int count = m_listeners.length - found - 1; | |||
System.arraycopy( m_listeners, found, listeners, found + 1, count ); | |||
m_listeners = listeners; | |||
} | |||
/** | |||
* Fire a projectStarted event. | |||
*/ | |||
public void projectStarted( final String projectName ) | |||
{ | |||
m_projectName = projectName; | |||
m_targetName = null; | |||
m_taskName = null; | |||
for( int i = 0; i < m_listeners.length; i++ ) | |||
{ | |||
m_listeners[ i ].projectStarted( this ); | |||
} | |||
} | |||
/** | |||
* Fire a projectFinished event. | |||
*/ | |||
public void projectFinished( final String projectName ) | |||
{ | |||
m_projectName = projectName; | |||
for( int i = 0; i < m_listeners.length; i++ ) | |||
{ | |||
m_listeners[ i ].projectFinished( this ); | |||
} | |||
m_projectName = null; | |||
m_targetName = null; | |||
m_taskName = null; | |||
} | |||
/** | |||
* Fire a targetStarted event. | |||
*/ | |||
public void targetStarted( final String projectName, final String targetName ) | |||
{ | |||
m_projectName = projectName; | |||
m_targetName = targetName; | |||
m_taskName = null; | |||
for( int i = 0; i < m_listeners.length; i++ ) | |||
{ | |||
m_listeners[ i ].targetStarted( this ); | |||
} | |||
} | |||
/** | |||
* Fire a targetFinished event. | |||
*/ | |||
public void targetFinished() | |||
{ | |||
for( int i = 0; i < m_listeners.length; i++ ) | |||
{ | |||
m_listeners[ i ].targetFinished( this ); | |||
} | |||
m_targetName = null; | |||
m_taskName = null; | |||
} | |||
/** | |||
* Fire a targetStarted event. | |||
*/ | |||
public void taskStarted( final String taskName ) | |||
{ | |||
m_taskName = taskName; | |||
for( int i = 0; i < m_listeners.length; i++ ) | |||
{ | |||
m_listeners[ i ].taskStarted( this ); | |||
} | |||
} | |||
/** | |||
* Fire a taskFinished event. | |||
*/ | |||
public void taskFinished() | |||
{ | |||
for( int i = 0; i < m_listeners.length; i++ ) | |||
{ | |||
m_listeners[ i ].taskFinished( this ); | |||
} | |||
m_taskName = null; | |||
} | |||
/** | |||
* Fire a log event. | |||
* | |||
* @param message the log message | |||
*/ | |||
public void log( String message, Throwable throwable ) | |||
{ | |||
m_message = message; | |||
m_throwable = throwable; | |||
try | |||
{ | |||
for( int i = 0; i < m_listeners.length; i++ ) | |||
{ | |||
m_listeners[ i ].log( this ); | |||
} | |||
} | |||
finally | |||
{ | |||
m_message = null; | |||
m_throwable = null; | |||
} | |||
} | |||
/** | |||
* Returns the message. | |||
*/ | |||
public String getMessage() | |||
{ | |||
return m_message; | |||
} | |||
/** | |||
* Returns the error that occurred. | |||
*/ | |||
public Throwable getThrowable() | |||
{ | |||
return m_throwable; | |||
} | |||
/** | |||
* Returns the name of the task. | |||
*/ | |||
public String getTaskName() | |||
{ | |||
return m_taskName; | |||
} | |||
/** | |||
* Returns the name of the target. | |||
*/ | |||
public String getTargetName() | |||
{ | |||
return m_targetName; | |||
} | |||
/** | |||
* Returns the name of the project. | |||
*/ | |||
public String getProjectName() | |||
{ | |||
return m_projectName; | |||
} | |||
} |
@@ -1,19 +0,0 @@ | |||
no-read.error=Unable to read library at {0}. | |||
no-library.error=Unable to locate Type Library {0}. | |||
no-deploy.error=Error deploying type library {0} at {1}. | |||
bad-deployer-config.error=Error configuring deployer. | |||
bad-frame.error=Error setting up ExecutionFrame. | |||
no-project.error=Project {0} not found. | |||
no-target.error=Target {0} not found. | |||
exec-target.notice=Executing project {0}, target {1}. | |||
exec-task.notice=Executing task {0}. | |||
target-dependency-cycle.error=Cycle in dependencies for target {0}. | |||
#DefaultTaskContext | |||
unknown-prop.error=Unknown property {0}. | |||
bad-property.error=Property {0} must have a value of type {1}. | |||
bad-property-name.error=Invalid property name. | |||
null-resolved-value.error=Value "{0}" resolved to null. | |||
bad-resolve.error=Unable to resolve value "{0}". | |||
bad-find-service.error=Could not find service "{0}". | |||
bad-service-class.error=Find service "{0}" but it was of type {1} where it was expected to be of type {2}. |
@@ -1,85 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.workspace; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.myrmidon.frontends.AbstractLogger; | |||
/** | |||
* A logger that just routes the messages to the ProjectListenerSupport. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
final class RoutingLogger | |||
extends AbstractLogger | |||
implements Logger | |||
{ | |||
/** | |||
* The endpoint of all the logging messages. | |||
*/ | |||
private final ProjectListenerSupport m_listenerSupport; | |||
/** | |||
* A wrapped logger that is used to determine which message types are | |||
* enabled. | |||
*/ | |||
private final Logger m_logger; | |||
/** | |||
* Create a Logger that routes messages at specified level | |||
* to specified support. | |||
* | |||
* @todo Use something other than a logger to figure out which messages | |||
* are enabled. | |||
*/ | |||
public RoutingLogger( final Logger logger, | |||
final ProjectListenerSupport listenerSupport ) | |||
{ | |||
m_listenerSupport = listenerSupport; | |||
m_logger = logger; | |||
} | |||
public boolean isDebugEnabled() | |||
{ | |||
return m_logger.isDebugEnabled(); | |||
} | |||
public boolean isInfoEnabled() | |||
{ | |||
return m_logger.isInfoEnabled(); | |||
} | |||
public boolean isWarnEnabled() | |||
{ | |||
return m_logger.isWarnEnabled(); | |||
} | |||
public boolean isErrorEnabled() | |||
{ | |||
return m_logger.isErrorEnabled(); | |||
} | |||
public boolean isFatalErrorEnabled() | |||
{ | |||
return m_logger.isFatalErrorEnabled(); | |||
} | |||
public Logger getChildLogger( final String name ) | |||
{ | |||
return new RoutingLogger( m_logger.getChildLogger( name ), m_listenerSupport ); | |||
} | |||
/** | |||
* Utility method to output messages. | |||
*/ | |||
protected void output( final String message, final Throwable throwable ) | |||
{ | |||
m_listenerSupport.log( message, throwable ); | |||
} | |||
} |
@@ -1,34 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.workspace; | |||
/** | |||
* An enumerated type that represents the dependency traversal state of a | |||
* target. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
final class TargetState | |||
{ | |||
private TargetState() | |||
{ | |||
} | |||
/** Target has not been started. */ | |||
public static final TargetState NOT_STARTED = new TargetState(); | |||
/** | |||
* Target has been started, and the dependencies of the target are being | |||
* traversed. | |||
*/ | |||
public static final TargetState TRAVERSING = new TargetState(); | |||
/** Target has been completed. */ | |||
public static final TargetState FINISHED = new TargetState(); | |||
} |
@@ -1,167 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.frontends; | |||
import org.apache.avalon.framework.logger.Logger; | |||
/** | |||
* A partial logger implementation. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public abstract class AbstractLogger | |||
implements Logger | |||
{ | |||
public static final int LEVEL_DEBUG = 0; | |||
public static final int LEVEL_INFO = 1; | |||
public static final int LEVEL_WARN = 2; | |||
public static final int LEVEL_ERROR = 3; | |||
public static final int LEVEL_FATAL = 4; | |||
/** | |||
* Log a debug message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void debug( final String message ) | |||
{ | |||
if( isDebugEnabled() ) | |||
{ | |||
output( message, null ); | |||
} | |||
} | |||
/** | |||
* Log a debug message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void debug( final String message, final Throwable throwable ) | |||
{ | |||
if( isDebugEnabled() ) | |||
{ | |||
output( message, throwable ); | |||
} | |||
} | |||
/** | |||
* Log a info message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void info( final String message ) | |||
{ | |||
if( isInfoEnabled() ) | |||
{ | |||
output( message, null ); | |||
} | |||
} | |||
/** | |||
* Log a info message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void info( final String message, final Throwable throwable ) | |||
{ | |||
if( isInfoEnabled() ) | |||
{ | |||
output( message, throwable ); | |||
} | |||
} | |||
/** | |||
* Log a warn message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void warn( final String message ) | |||
{ | |||
if( isWarnEnabled() ) | |||
{ | |||
output( message, null ); | |||
} | |||
} | |||
/** | |||
* Log a warn message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void warn( final String message, final Throwable throwable ) | |||
{ | |||
if( isWarnEnabled() ) | |||
{ | |||
output( message, throwable ); | |||
} | |||
} | |||
/** | |||
* Log a error message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void error( final String message ) | |||
{ | |||
if( isErrorEnabled() ) | |||
{ | |||
output( message, null ); | |||
} | |||
} | |||
/** | |||
* Log a error message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void error( final String message, final Throwable throwable ) | |||
{ | |||
if( isErrorEnabled() ) | |||
{ | |||
output( message, throwable ); | |||
} | |||
} | |||
/** | |||
* Log a fatalError message. | |||
* | |||
* @param message the message | |||
*/ | |||
public void fatalError( final String message ) | |||
{ | |||
if( isFatalErrorEnabled() ) | |||
{ | |||
output( message, null ); | |||
} | |||
} | |||
/** | |||
* Log a fatalError message. | |||
* | |||
* @param message the message | |||
* @param throwable the throwable | |||
*/ | |||
public void fatalError( final String message, final Throwable throwable ) | |||
{ | |||
if( isFatalErrorEnabled() ) | |||
{ | |||
output( message, throwable ); | |||
} | |||
} | |||
/** | |||
* Utility method to output messages. | |||
*/ | |||
protected abstract void output( final String message, | |||
final Throwable throwable ); | |||
} |
@@ -1,124 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.frontends; | |||
import org.apache.avalon.framework.ExceptionUtil; | |||
import org.apache.avalon.framework.logger.Logger; | |||
/** | |||
* A basic logger that just prints out messages to <code>System.out</code>. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class BasicLogger | |||
extends AbstractLogger | |||
implements Logger | |||
{ | |||
/** | |||
* The string prefixed to all log messages. | |||
*/ | |||
private final String m_prefix; | |||
/** | |||
* The level at which messages start becoming logged. | |||
*/ | |||
private final int m_logLevel; | |||
/** | |||
* Create a logger that has specified prefix and is logging | |||
* at specified level. | |||
*/ | |||
public BasicLogger( final String prefix, final int logLevel ) | |||
{ | |||
m_prefix = prefix; | |||
m_logLevel = logLevel; | |||
} | |||
/** | |||
* Determine if messages of priority "debug" will be logged. | |||
* | |||
* @return true if "debug" messages will be logged | |||
*/ | |||
public boolean isDebugEnabled() | |||
{ | |||
return m_logLevel <= LEVEL_DEBUG; | |||
} | |||
/** | |||
* Determine if messages of priority "info" will be logged. | |||
* | |||
* @return true if "info" messages will be logged | |||
*/ | |||
public boolean isInfoEnabled() | |||
{ | |||
return m_logLevel <= LEVEL_INFO; | |||
} | |||
/** | |||
* Determine if messages of priority "warn" will be logged. | |||
* | |||
* @return true if "warn" messages will be logged | |||
*/ | |||
public boolean isWarnEnabled() | |||
{ | |||
return m_logLevel <= LEVEL_WARN; | |||
} | |||
/** | |||
* Determine if messages of priority "error" will be logged. | |||
* | |||
* @return true if "error" messages will be logged | |||
*/ | |||
public boolean isErrorEnabled() | |||
{ | |||
return m_logLevel <= LEVEL_ERROR; | |||
} | |||
/** | |||
* Determine if messages of priority "fatalError" will be logged. | |||
* | |||
* @return true if "fatalError" messages will be logged | |||
*/ | |||
public boolean isFatalErrorEnabled() | |||
{ | |||
return m_logLevel <= LEVEL_FATAL; | |||
} | |||
/** | |||
* Create a new child logger. | |||
* The name of the child logger is [current-loggers-name].[passed-in-name] | |||
* | |||
* @param name the subname of this logger | |||
* @return the new logger | |||
* @exception IllegalArgumentException if name has an empty element name | |||
*/ | |||
public Logger getChildLogger( final String name ) | |||
{ | |||
return new BasicLogger( m_prefix + "." + name, m_logLevel ); | |||
} | |||
/** | |||
* Utility method to output messages. | |||
*/ | |||
protected void output( final String message, final Throwable throwable ) | |||
{ | |||
final StringBuffer sb = new StringBuffer( m_prefix ); | |||
if( null != message ) | |||
{ | |||
sb.append( message ); | |||
} | |||
System.out.println( sb ); | |||
if( null != throwable ) | |||
{ | |||
final String stackTrace = ExceptionUtil.printStackTrace( throwable, 8, true, true ); | |||
System.out.println( stackTrace ); | |||
} | |||
} | |||
} |
@@ -1,477 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.frontends; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
import java.io.InputStreamReader; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.avalon.excalibur.cli.CLArgsParser; | |||
import org.apache.avalon.excalibur.cli.CLOption; | |||
import org.apache.avalon.excalibur.cli.CLOptionDescriptor; | |||
import org.apache.avalon.excalibur.cli.CLUtil; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.CascadingException; | |||
import org.apache.avalon.framework.ExceptionUtil; | |||
import org.apache.myrmidon.Constants; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.interfaces.executor.Executor; | |||
/** | |||
* The class to kick the tires and light the fires. | |||
* Starts myrmidon, loads ProjectBuilder, builds project then uses ProjectManager | |||
* to run project. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class CLIMain | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( CLIMain.class ); | |||
//defines for the Command Line options | |||
private static final int HELP_OPT = 'h'; | |||
private static final int QUIET_OPT = 'q'; | |||
private static final int VERBOSE_OPT = 'v'; | |||
private static final int FILE_OPT = 'f'; | |||
private static final int LOG_LEVEL_OPT = 'l'; | |||
private static final int DEFINE_OPT = 'D'; | |||
private static final int BUILDER_PARAM_OPT = 'B'; | |||
private static final int NO_PREFIX_OPT = 'p'; | |||
private static final int VERSION_OPT = 1; | |||
private static final int LISTENER_OPT = 2; | |||
private static final int TASKLIB_DIR_OPT = 5; | |||
private static final int EXTLIB_DIR_OPT = 6; | |||
private static final int INCREMENTAL_OPT = 7; | |||
private static final int HOME_DIR_OPT = 8; | |||
private static final int DRY_RUN_OPT = 9; | |||
private static final int DEBUG_OPT = 10; | |||
private static final int TYPE_OPT = 11; | |||
//incompatable options for info options | |||
private static final int[] INFO_OPT_INCOMPAT = new int[] | |||
{ | |||
HELP_OPT, QUIET_OPT, VERBOSE_OPT, FILE_OPT, | |||
LOG_LEVEL_OPT, BUILDER_PARAM_OPT, NO_PREFIX_OPT, | |||
VERSION_OPT, LISTENER_OPT, TASKLIB_DIR_OPT, EXTLIB_DIR_OPT, | |||
INCREMENTAL_OPT, HOME_DIR_OPT, DRY_RUN_OPT, TYPE_OPT | |||
}; | |||
//incompatable options for other logging options | |||
private static final int[] LOG_OPT_INCOMPAT = new int[] | |||
{ | |||
QUIET_OPT, VERBOSE_OPT, LOG_LEVEL_OPT, DEBUG_OPT | |||
}; | |||
//incompatible options for listener options | |||
private static final int[] LISTENER_OPT_INCOMPAT = new int[] | |||
{ | |||
LISTENER_OPT, NO_PREFIX_OPT | |||
}; | |||
///List of targets supplied on command line to execute | |||
private ArrayList m_targets = new ArrayList(); | |||
///Determine whether tasks are actually executed | |||
private boolean m_dryRun = false; | |||
///Enables incremental mode | |||
private boolean m_incremental; | |||
///The launcher | |||
private EmbeddedAnt m_embedded = new EmbeddedAnt(); | |||
///Log level to use | |||
private static int m_priority = BasicLogger.LEVEL_WARN; | |||
/** | |||
* Main entry point called to run standard Myrmidon. | |||
* | |||
* @param args the args | |||
*/ | |||
public static void main( final String[] args ) | |||
{ | |||
final Map properties = new HashMap(); | |||
properties.put( "myrmidon.home", new File( "." ) ); | |||
main( properties, args ); | |||
} | |||
/** | |||
* Main entry point called to run standard Myrmidon. | |||
* | |||
* @param args the args | |||
*/ | |||
public static void main( final Map properties, final String[] args ) | |||
{ | |||
int exitCode = 0; | |||
final CLIMain main = new CLIMain(); | |||
try | |||
{ | |||
main.execute( properties, args ); | |||
} | |||
catch( final Throwable throwable ) | |||
{ | |||
main.reportError( throwable ); | |||
exitCode = -1; | |||
} | |||
finally | |||
{ | |||
System.exit( exitCode ); | |||
} | |||
} | |||
/** | |||
* Display usage report. | |||
* | |||
*/ | |||
private void usage( final CLOptionDescriptor[] options ) | |||
{ | |||
System.out.println( "ant [options] [targets]" ); | |||
System.out.println( "\tAvailable options:" ); | |||
System.out.println( CLUtil.describeOptions( options ) ); | |||
} | |||
/** | |||
* Initialise the options for command line parser. | |||
*/ | |||
private CLOptionDescriptor[] createCLOptions() | |||
{ | |||
//TODO: localise | |||
final CLOptionDescriptor[] options = { | |||
new CLOptionDescriptor( "help", | |||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||
HELP_OPT, | |||
REZ.getString( "help.opt" ), | |||
INFO_OPT_INCOMPAT ), | |||
new CLOptionDescriptor( "file", | |||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||
FILE_OPT, | |||
REZ.getString( "file.opt" ) ), | |||
new CLOptionDescriptor( "log-level", | |||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||
LOG_LEVEL_OPT, | |||
REZ.getString( "log-level.opt" ), | |||
LOG_OPT_INCOMPAT ), | |||
new CLOptionDescriptor( "quiet", | |||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||
QUIET_OPT, | |||
REZ.getString( "quiet.opt" ), | |||
LOG_OPT_INCOMPAT ), | |||
new CLOptionDescriptor( "verbose", | |||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||
VERBOSE_OPT, | |||
REZ.getString( "verbose.opt" ), | |||
LOG_OPT_INCOMPAT ), | |||
new CLOptionDescriptor( "debug", | |||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||
DEBUG_OPT, | |||
REZ.getString( "debug.opt" ), | |||
LOG_OPT_INCOMPAT ), | |||
new CLOptionDescriptor( "listener", | |||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||
LISTENER_OPT, | |||
REZ.getString( "listener.opt" ), | |||
LISTENER_OPT_INCOMPAT ), | |||
new CLOptionDescriptor( "noprefix", | |||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||
NO_PREFIX_OPT, | |||
REZ.getString( "noprefix.opt" ), | |||
LISTENER_OPT_INCOMPAT ), | |||
new CLOptionDescriptor( "version", | |||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||
VERSION_OPT, | |||
REZ.getString( "version.opt" ), | |||
INFO_OPT_INCOMPAT ), | |||
new CLOptionDescriptor( "antlib-path", | |||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||
TASKLIB_DIR_OPT, | |||
REZ.getString( "tasklib.opt" ) ), | |||
new CLOptionDescriptor( "ext-path", | |||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||
EXTLIB_DIR_OPT, | |||
REZ.getString( "extlib.opt" ) ), | |||
new CLOptionDescriptor( "incremental", | |||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||
INCREMENTAL_OPT, | |||
REZ.getString( "incremental.opt" ) ), | |||
new CLOptionDescriptor( "ant-home", | |||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||
HOME_DIR_OPT, | |||
REZ.getString( "home.opt" ) ), | |||
new CLOptionDescriptor( "define", | |||
CLOptionDescriptor.ARGUMENTS_REQUIRED_2, | |||
DEFINE_OPT, | |||
REZ.getString( "define.opt" ), | |||
new int[ 0 ] ), | |||
new CLOptionDescriptor( "builder-parameter", | |||
CLOptionDescriptor.ARGUMENTS_REQUIRED_2, | |||
BUILDER_PARAM_OPT, | |||
REZ.getString( "build.opt" ) ), | |||
new CLOptionDescriptor( "dry-run", | |||
CLOptionDescriptor.ARGUMENT_DISALLOWED, | |||
DRY_RUN_OPT, | |||
REZ.getString( "dry-run.opt" ) ), | |||
new CLOptionDescriptor( "type", | |||
CLOptionDescriptor.ARGUMENT_REQUIRED, | |||
TYPE_OPT, | |||
REZ.getString( "type.opt" ) ) | |||
}; | |||
return options; | |||
} | |||
private boolean parseCommandLineOptions( final String[] args ) | |||
throws Exception | |||
{ | |||
final CLOptionDescriptor[] options = createCLOptions(); | |||
final CLArgsParser parser = new CLArgsParser( args, options ); | |||
if( null != parser.getErrorString() ) | |||
{ | |||
final String message = REZ.getString( "error-message", parser.getErrorString() ); | |||
throw new Exception( message ); | |||
} | |||
final List clOptions = parser.getArguments(); | |||
final int size = clOptions.size(); | |||
for( int i = 0; i < size; i++ ) | |||
{ | |||
final CLOption option = (CLOption)clOptions.get( i ); | |||
switch( option.getId() ) | |||
{ | |||
case HELP_OPT: | |||
usage( options ); | |||
return false; | |||
case VERSION_OPT: | |||
System.out.println( Constants.BUILD_DESCRIPTION ); | |||
return false; | |||
case HOME_DIR_OPT: | |||
m_embedded.setEmbeddorProperty( "myrmidon.home", option.getArgument() ); | |||
break; | |||
case TASKLIB_DIR_OPT: | |||
m_embedded.setEmbeddorProperty( "myrmidon.antlib.path", option.getArgument() ); | |||
break; | |||
case EXTLIB_DIR_OPT: | |||
m_embedded.setEmbeddorProperty( "myrmidon.ext.path", option.getArgument() ); | |||
break; | |||
case LOG_LEVEL_OPT: | |||
m_priority = mapLogLevel( option.getArgument() ); | |||
break; | |||
case VERBOSE_OPT: | |||
m_priority = BasicLogger.LEVEL_INFO; | |||
break; | |||
case DEBUG_OPT: | |||
m_priority = BasicLogger.LEVEL_DEBUG; | |||
break; | |||
case QUIET_OPT: | |||
m_priority = BasicLogger.LEVEL_ERROR; | |||
break; | |||
case INCREMENTAL_OPT: | |||
m_incremental = true; | |||
break; | |||
case FILE_OPT: | |||
m_embedded.setProjectFile( option.getArgument() ); | |||
break; | |||
case LISTENER_OPT: | |||
m_embedded.setProjectListener( option.getArgument() ); | |||
break; | |||
case NO_PREFIX_OPT: | |||
m_embedded.setProjectListener( "noprefix" ); | |||
break; | |||
case DEFINE_OPT: | |||
m_embedded.setWorkspaceProperty( option.getArgument( 0 ), option.getArgument( 1 ) ); | |||
break; | |||
case BUILDER_PARAM_OPT: | |||
m_embedded.setBuilderProperty( option.getArgument( 0 ), option.getArgument( 1 ) ); | |||
break; | |||
case DRY_RUN_OPT: | |||
m_dryRun = true; | |||
break; | |||
case TYPE_OPT: | |||
m_embedded.setProjectType( option.getArgument( 0 ) ); | |||
break; | |||
case 0: | |||
m_targets.add( option.getArgument() ); | |||
break; | |||
} | |||
} | |||
return true; | |||
} | |||
private void execute( final Map properties, final String[] args ) | |||
throws Exception | |||
{ | |||
try | |||
{ | |||
// Set system properties set up by launcher | |||
m_embedded.setHomeDirectory( (File)properties.get( "myrmidon.home" ) ); | |||
// Command line | |||
if( !parseCommandLineOptions( args ) ) | |||
{ | |||
return; | |||
} | |||
// Setup logging | |||
final BasicLogger logger = new BasicLogger( "[myrmidon] ", m_priority ); | |||
m_embedded.enableLogging( logger ); | |||
if( m_dryRun ) | |||
{ | |||
m_embedded.setEmbeddorProperty( Executor.ROLE, | |||
"org.apache.myrmidon.components.executor.PrintingExecutor" ); | |||
} | |||
// Set the common classloader | |||
final ClassLoader sharedClassLoader = (ClassLoader)properties.get( "myrmidon.shared.classloader" ); | |||
m_embedded.setSharedClassLoader( sharedClassLoader ); | |||
//loop over build if we are in incremental mode.. | |||
if( !m_incremental ) | |||
{ | |||
executeBuild(); | |||
} | |||
else | |||
{ | |||
executeIncrementalBuild(); | |||
} | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "build-failed.error" ); | |||
throw new CascadingException( message, e ); | |||
} | |||
finally | |||
{ | |||
m_embedded.stop(); | |||
} | |||
} | |||
private void executeIncrementalBuild() | |||
throws Exception | |||
{ | |||
BufferedReader reader = null; | |||
while( true ) | |||
{ | |||
try | |||
{ | |||
executeBuild(); | |||
} | |||
catch( final TaskException te ) | |||
{ | |||
reportError( te ); | |||
} | |||
final String message = REZ.getString( "repeat.notice" ); | |||
System.out.println( message ); | |||
if( null == reader ) | |||
{ | |||
reader = new BufferedReader( new InputStreamReader( System.in ) ); | |||
} | |||
String line = reader.readLine(); | |||
if( line.equalsIgnoreCase( "no" ) ) | |||
{ | |||
break; | |||
} | |||
} | |||
} | |||
private void executeBuild() throws Exception | |||
{ | |||
//actually do the build ... | |||
final String[] targets = (String[])m_targets.toArray( new String[ m_targets.size() ] ); | |||
m_embedded.executeTargets( targets ); | |||
} | |||
/** | |||
* Builds the error message for an exception | |||
*/ | |||
private void reportError( final Throwable throwable ) | |||
{ | |||
// Build the message | |||
final String message; | |||
if( m_priority <= BasicLogger.LEVEL_INFO ) | |||
{ | |||
// Verbose mode - include the stack traces | |||
message = ExceptionUtil.printStackTrace( throwable, 8, true, true ); | |||
} | |||
else | |||
{ | |||
// Build the message | |||
final StringBuffer buffer = new StringBuffer(); | |||
buffer.append( throwable.getMessage() ); | |||
for( Throwable current = ExceptionUtil.getCause( throwable, true ); | |||
current != null; | |||
current = ExceptionUtil.getCause( current, true ) ) | |||
{ | |||
final String causeMessage = REZ.getString( "cause.error", current.getMessage() ); | |||
buffer.append( causeMessage ); | |||
} | |||
message = buffer.toString(); | |||
} | |||
// Write the message out | |||
System.err.println( message ); | |||
} | |||
/** | |||
* Sets the log level. | |||
*/ | |||
private int mapLogLevel( final String logLevel ) | |||
throws Exception | |||
{ | |||
final String logLevelCapitalized = logLevel.toUpperCase(); | |||
if( "DEBUG".equals( logLevelCapitalized ) ) | |||
{ | |||
return BasicLogger.LEVEL_DEBUG; | |||
} | |||
else if( "VERBOSE".equals( logLevelCapitalized ) ) | |||
{ | |||
return BasicLogger.LEVEL_INFO; | |||
} | |||
else if( "INFO".equals( logLevelCapitalized ) ) | |||
{ | |||
return BasicLogger.LEVEL_WARN; | |||
} | |||
else if( "WARN".equals( logLevelCapitalized ) ) | |||
{ | |||
return BasicLogger.LEVEL_ERROR; | |||
} | |||
else if( "ERROR".equals( logLevelCapitalized ) ) | |||
{ | |||
return BasicLogger.LEVEL_FATAL; | |||
} | |||
else | |||
{ | |||
final String message = REZ.getString( "bad-loglevel.error", logLevel ); | |||
throw new Exception( message ); | |||
} | |||
} | |||
} |
@@ -1,420 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.frontends; | |||
import java.io.File; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.excalibur.io.FileUtil; | |||
import org.apache.avalon.excalibur.util.StringUtil; | |||
import org.apache.avalon.framework.activity.Disposable; | |||
import org.apache.avalon.framework.activity.Initializable; | |||
import org.apache.avalon.framework.activity.Startable; | |||
import org.apache.avalon.framework.context.Context; | |||
import org.apache.avalon.framework.context.Contextualizable; | |||
import org.apache.avalon.framework.context.DefaultContext; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.interfaces.embeddor.Embeddor; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||
import org.apache.myrmidon.listeners.ProjectListener; | |||
/** | |||
* A utility class, that takes care of launching Myrmidon, and building and | |||
* executing a project. | |||
* | |||
* <p>To use this class, create an instance and configure. To execute | |||
* targets in a project, use the {@link #executeTargets} method. This can | |||
* be done one or more times. Finally, call the {@link #stop} method to | |||
* clean-up. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class EmbeddedAnt | |||
extends AbstractLogEnabled | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( EmbeddedAnt.class ); | |||
private static final String DEFAULT_EMBEDDOR_CLASS = | |||
"org.apache.myrmidon.components.embeddor.DefaultEmbeddor"; | |||
private final ArrayList m_listeners = new ArrayList(); | |||
private final Parameters m_builderProps = new Parameters(); | |||
private final Map m_embeddorParameters = new HashMap(); | |||
private final Map m_workspaceProperties = new HashMap(); | |||
private String m_projectFile = "build.ant"; | |||
private Project m_project; | |||
private String m_listenerName = "default"; | |||
private ClassLoader m_sharedClassLoader; | |||
private Embeddor m_embeddor; | |||
private File m_homeDir; | |||
private String m_projectType; | |||
/** | |||
* Sets the Myrmidon home directory. Default is to use the current | |||
* directory. | |||
* | |||
* @todo Autodetect myrmidon home, rather than using current directory | |||
* as the default (which is a dud default). | |||
*/ | |||
public void setHomeDirectory( final File homeDir ) | |||
{ | |||
m_homeDir = homeDir.getAbsoluteFile(); | |||
} | |||
/** | |||
* Sets the project file to execute. Default is 'build.ant'. | |||
*/ | |||
public void setProjectFile( final String projectFile ) | |||
{ | |||
m_projectFile = projectFile; | |||
m_project = null; | |||
} | |||
/** | |||
* Sets the project file type. Ignored if {@link #setProject} is used. | |||
* Set to null to use the default project type. | |||
*/ | |||
public void setProjectType( final String projectType ) | |||
{ | |||
m_projectType = projectType; | |||
} | |||
/** | |||
* Sets the project to execute. This method can be used instead of | |||
* {@link #setProjectFile}, for projects models that are built | |||
* programmatically. | |||
*/ | |||
public void setProject( final Project project ) | |||
{ | |||
m_projectFile = null; | |||
m_project = project; | |||
} | |||
/** | |||
* Sets the name of the project listener to use. Set to null to disable | |||
* the project listener. | |||
*/ | |||
public void setProjectListener( final String listener ) | |||
{ | |||
m_listenerName = listener; | |||
} | |||
/** | |||
* Adds a project listener. | |||
*/ | |||
public void addProjectListener( final ProjectListener listener ) | |||
{ | |||
m_listeners.add( listener ); | |||
} | |||
/** | |||
* Sets a workspace property. These are inherited by all projects executed | |||
* by this embeddor. | |||
*/ | |||
public void setWorkspaceProperty( final String name, final Object value ) | |||
{ | |||
m_workspaceProperties.put( name, value ); | |||
} | |||
/** | |||
* Sets a project builder property. These are used by the project builder | |||
* when it is parsing the project file. | |||
*/ | |||
public void setBuilderProperty( final String name, final Object value ) | |||
{ | |||
// TODO - Make properties Objects, not Strings | |||
m_builderProps.setParameter( name, value.toString() ); | |||
} | |||
/** | |||
* Sets a task engine property. These are used to configure the task engine. | |||
* | |||
* @todo Make this method actually work with objects... | |||
*/ | |||
public void setEmbeddorProperty( final String name, final Object value ) | |||
{ | |||
m_embeddorParameters.put( name, value.toString() ); | |||
} | |||
/** | |||
* Sets the shared classloader, which is used as the parent classloader | |||
* for all antlibs. Default is to use the context classloader. | |||
*/ | |||
public void setSharedClassLoader( final ClassLoader classLoader ) | |||
{ | |||
m_sharedClassLoader = classLoader; | |||
} | |||
/** | |||
* Executes a set of targets in the project. This method may be called | |||
* multiple times. | |||
*/ | |||
public void executeTargets( final String[] targets ) throws Exception | |||
{ | |||
Map embeddorParameters = new HashMap( m_embeddorParameters ); | |||
setupPaths( embeddorParameters ); | |||
if( m_sharedClassLoader != null ) | |||
{ | |||
embeddorParameters.put( "myrmidon.shared.classloader", m_sharedClassLoader ); | |||
} | |||
// Prepare the embeddor, and project model | |||
final Embeddor embeddor = prepareEmbeddor( embeddorParameters ); | |||
final Project project = prepareProjectModel( embeddor ); | |||
// Create a new workspace | |||
final Workspace workspace = embeddor.createWorkspace( m_workspaceProperties ); | |||
prepareListeners( embeddor, workspace ); | |||
//execute the project | |||
executeTargets( workspace, project, targets ); | |||
} | |||
/** | |||
* Shuts down the task engine, after the project has been executed. | |||
*/ | |||
public void stop() throws Exception | |||
{ | |||
try | |||
{ | |||
if( m_embeddor != null ) | |||
{ | |||
if( m_embeddor instanceof Startable ) | |||
{ | |||
( (Startable)m_embeddor ).stop(); | |||
} | |||
if( m_embeddor instanceof Disposable ) | |||
{ | |||
( (Disposable)m_embeddor ).dispose(); | |||
} | |||
} | |||
} | |||
finally | |||
{ | |||
m_embeddor = null; | |||
m_project = null; | |||
m_listeners.clear(); | |||
} | |||
} | |||
/** | |||
* Actually do the build. | |||
*/ | |||
private void executeTargets( final Workspace workspace, | |||
final Project project, | |||
final String[] targets ) | |||
throws TaskException | |||
{ | |||
//if we didn't specify a target, then choose default | |||
if( targets == null || targets.length == 0 ) | |||
{ | |||
workspace.executeProject( project, project.getDefaultTargetName() ); | |||
} | |||
else | |||
{ | |||
for( int i = 0; i < targets.length; i++ ) | |||
{ | |||
workspace.executeProject( project, targets[ i ] ); | |||
} | |||
} | |||
} | |||
/** | |||
* Make sure myrmidon home directory has been specified, and is a | |||
* directory. Set the paths that the embeddor expects. | |||
*/ | |||
private void setupPaths( Map parameters ) throws Exception | |||
{ | |||
if( m_homeDir == null ) | |||
{ | |||
m_homeDir = new File( "." ).getAbsoluteFile(); | |||
} | |||
checkDirectory( m_homeDir, "home-dir.name" ); | |||
parameters.put( "myrmidon.home", m_homeDir ); | |||
if( getLogger().isInfoEnabled() ) | |||
{ | |||
final String message = REZ.getString( "homedir.notice", m_homeDir ); | |||
getLogger().info( message ); | |||
} | |||
// Build the lib path | |||
String path = (String)parameters.get( "myrmidon.lib.path" ); | |||
File[] dirs = buildPath( m_homeDir, path, "lib", "lib-dir.name" ); | |||
parameters.put( "myrmidon.lib.path", dirs ); | |||
// Build the antlib search path | |||
path = (String)parameters.get( "myrmidon.antlib.path" ); | |||
dirs = buildPath( m_homeDir, path, "ext", "task-lib-dir.name" ); | |||
parameters.put( "myrmidon.antlib.path", dirs ); | |||
// Build the extension search path | |||
path = (String)parameters.get( "myrmidon.ext.path" ); | |||
dirs = buildPath( m_homeDir, path, "ext", "ext-dir.name" ); | |||
parameters.put( "myrmidon.ext.path", dirs ); | |||
} | |||
/** | |||
* Prepares and returns the embeddor to use. | |||
*/ | |||
private Embeddor prepareEmbeddor( final Map parameters ) | |||
throws Exception | |||
{ | |||
if( m_embeddor == null ) | |||
{ | |||
m_embeddor = createEmbeddor(); | |||
setupLogger( m_embeddor ); | |||
if( m_embeddor instanceof Contextualizable ) | |||
{ | |||
final Context context = new DefaultContext( parameters ); | |||
( (Contextualizable)m_embeddor ).contextualize( context ); | |||
} | |||
if( m_embeddor instanceof Initializable ) | |||
{ | |||
( (Initializable)m_embeddor ).initialize(); | |||
} | |||
if( m_embeddor instanceof Startable ) | |||
{ | |||
( (Startable)m_embeddor ).start(); | |||
} | |||
} | |||
return m_embeddor; | |||
} | |||
/** | |||
* Creates the embeddor. | |||
*/ | |||
private Embeddor createEmbeddor() | |||
throws Exception | |||
{ | |||
final Class clazz = Class.forName( DEFAULT_EMBEDDOR_CLASS ); | |||
return (Embeddor)clazz.newInstance(); | |||
} | |||
/** | |||
* Prepares and returns the project listener to use. | |||
*/ | |||
private void prepareListeners( final Embeddor embeddor, | |||
final Workspace workspace ) | |||
throws Exception | |||
{ | |||
if( m_listenerName != null ) | |||
{ | |||
final ProjectListener listener = embeddor.createListener( m_listenerName ); | |||
workspace.addProjectListener( listener ); | |||
} | |||
final int count = m_listeners.size(); | |||
for( int i = 0; i < count; i++ ) | |||
{ | |||
final ProjectListener listener = (ProjectListener)m_listeners.get( i ); | |||
workspace.addProjectListener( listener ); | |||
} | |||
} | |||
/** | |||
* Prepares and returns the project model. | |||
*/ | |||
private Project prepareProjectModel( final Embeddor embeddor ) throws Exception | |||
{ | |||
if( m_project == null ) | |||
{ | |||
final File buildFile = getProjectFile(); | |||
m_project = embeddor.createProject( buildFile.toString(), m_projectType, m_builderProps ); | |||
} | |||
return m_project; | |||
} | |||
/** | |||
* Locates the project file | |||
*/ | |||
private File getProjectFile() throws Exception | |||
{ | |||
final File projectFile = ( new File( m_projectFile ) ).getCanonicalFile(); | |||
if( !projectFile.isFile() ) | |||
{ | |||
final String message = REZ.getString( "bad-file.error", projectFile ); | |||
throw new Exception( message ); | |||
} | |||
if( getLogger().isInfoEnabled() ) | |||
{ | |||
final String message = REZ.getString( "buildfile.notice", projectFile ); | |||
getLogger().info( message ); | |||
} | |||
return projectFile; | |||
} | |||
/** | |||
* Resolve a directory relative to another base directory. | |||
*/ | |||
private File[] buildPath( final File baseDir, | |||
final String path, | |||
final String defaultPath, | |||
final String name ) | |||
throws Exception | |||
{ | |||
// Build the canonical list of files | |||
final ArrayList files = new ArrayList(); | |||
// Add the default path | |||
files.add( FileUtil.resolveFile( baseDir, defaultPath ) ); | |||
// Add the additional path | |||
if( path != null ) | |||
{ | |||
final String[] split = StringUtil.split( path, File.pathSeparator ); | |||
for( int i = 0; i < split.length; i++ ) | |||
{ | |||
final String s = split[ i ]; | |||
final File file = new File( s ).getAbsoluteFile(); | |||
files.add( file ); | |||
} | |||
} | |||
// Check each one | |||
for( int i = 0; i < files.size(); i++ ) | |||
{ | |||
File file = (File)files.get( i ); | |||
checkDirectory( file, name ); | |||
} | |||
return (File[])files.toArray( new File[ files.size() ] ); | |||
} | |||
/** | |||
* Verify file is a directory else throw an exception. | |||
*/ | |||
private void checkDirectory( final File file, final String name ) | |||
throws Exception | |||
{ | |||
if( !file.exists() ) | |||
{ | |||
final String nameStr = REZ.getString( name ); | |||
final String message = REZ.getString( "file-no-exist.error", nameStr, file ); | |||
throw new Exception( message ); | |||
} | |||
else if( !file.isDirectory() ) | |||
{ | |||
final String nameStr = REZ.getString( name ); | |||
final String message = REZ.getString( "file-not-dir.error", nameStr, file ); | |||
throw new Exception( message ); | |||
} | |||
} | |||
} |
@@ -1,35 +0,0 @@ | |||
error-message=Error: {0}. | |||
help.opt=Display this help message. | |||
file.opt=Specify the build file. | |||
log-level.opt=Specify the verbosity level at which to log messages. (DEBUG|VERBOSE|INFO|WARN|ERROR). | |||
quiet.opt=Equivalent to --log-level=ERROR. | |||
verbose.opt=Equivalent to --log-level=VERBOSE. | |||
debug.opt=Equivalent to --log-level=DEBUG. | |||
listener.opt=Specify the listener for log events. | |||
noprefix.opt=Do not prefix output with the task name. Equivalent to --listener noprefix. | |||
version.opt=Display version. | |||
tasklib.opt=Specify the path to use to search for antlib libraries. | |||
extlib.opt=Specify the path to use to search for optional packages. | |||
incremental.opt=Run in incremental mode. | |||
home.opt=Specify Ant home directory. | |||
define.opt=Define a property (ie -Dfoo=var). | |||
build.opt=Define a builder parameter (ie -Bfoo=var). | |||
dry-run.opt=Do not execute tasks - just print them out. | |||
type.opt=Specify the project file type. | |||
file-no-exist.error={0} {1} does not exist. | |||
file-not-dir.error={0} {1} is not a directory. | |||
bad-file.error=File {0} is not a file or doesn't exist. | |||
bad-loglevel.error=Unknown log level - {0}. | |||
build-failed.error=BUILD FAILED. | |||
cause.error=\nReason: {0} | |||
repeat.notice=Continue ? (Enter no to stop) | |||
homedir.notice=Ant Home Directory: {0} | |||
buildfile.notice=Ant Build File: {0} | |||
home-dir.name=Ant home directory | |||
lib-dir.name=Library directory | |||
task-lib-dir.name=Antlib directory | |||
ext-dir.name=Extension directory |
@@ -1,56 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces; | |||
/** | |||
* An exception thrown by a Myrmidon component. This is a convenience | |||
* class, which can be sub-classes to create exceptions for specific components. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ComponentException | |||
extends Exception | |||
{ | |||
/** | |||
* The Throwable that caused this exception to be thrown. | |||
*/ | |||
private final Throwable m_throwable; | |||
/** | |||
* Constructs a non-cascaded exception. | |||
* | |||
* @param message The detail message for this exception. | |||
*/ | |||
public ComponentException( final String message ) | |||
{ | |||
this( message, null ); | |||
} | |||
/** | |||
* Constructs a cascaded exception. | |||
* | |||
* @param message The detail message for this exception. | |||
* @param throwable the root cause of the exception | |||
*/ | |||
public ComponentException( final String message, final Throwable throwable ) | |||
{ | |||
super( message ); | |||
m_throwable = throwable; | |||
} | |||
/** | |||
* Retrieve root cause of the exception. | |||
* | |||
* @return the root cause | |||
*/ | |||
public final Throwable getCause() | |||
{ | |||
return m_throwable; | |||
} | |||
} |
@@ -1,59 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.aspect; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.aspects.AspectHandler; | |||
/** | |||
* Manage and propogate Aspects.. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface AspectManager | |||
extends AspectHandler | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = AspectManager.class.getName(); | |||
/** | |||
* @return The names of all AspectHandlers managed. | |||
*/ | |||
String[] getNames(); | |||
/** | |||
* Dispatches aspect settings to the named AspectHandler. | |||
* @param name The name of the AspectHandler to recieve the settings. | |||
* @param parameters The parameter settings. | |||
* @param elements The nested Configuration settings. | |||
* @throws TaskException if the named AspectHandler doesn't exist, | |||
* or it cannot handle the settings. | |||
*/ | |||
void dispatchAspectSettings( String name, Parameters parameters, Configuration[] elements ) | |||
throws TaskException; | |||
/** | |||
* Adds a named aspect handler to the manager. | |||
* @param name The name used to lookup the aspect handler. | |||
* @param handler The aspect handler to add. | |||
* @throws TaskException If an error occurs. | |||
*/ | |||
void addAspectHandler( String name, AspectHandler handler ) | |||
throws TaskException; | |||
/** | |||
* Removes a named aspect handler from the manager. | |||
* @param name The name of the handler to remove. | |||
* @throws TaskException If the named handler doesn't exist. | |||
*/ | |||
void removeAspectHandler( String name ) | |||
throws TaskException; | |||
} |
@@ -1,33 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.builder; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
/** | |||
* Interface implemented by components that build projects from sources. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
* @ant:role shorthand="project-builder" | |||
*/ | |||
public interface ProjectBuilder | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = ProjectBuilder.class.getName(); | |||
/** | |||
* build a project from source. | |||
* | |||
* @param source the project file path. | |||
* @return the constructed Project | |||
* @exception ProjectException if an error occurs | |||
*/ | |||
Project build( String source ) | |||
throws ProjectException; | |||
} |
@@ -1,41 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.builder; | |||
import org.apache.myrmidon.interfaces.ComponentException; | |||
/** | |||
* A cascading exception thrown on a problem constructing a Project model. | |||
* | |||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ProjectException | |||
extends ComponentException | |||
{ | |||
/** | |||
* Constructs a non-cascaded exception. | |||
* | |||
* @param message The detail message for this exception. | |||
*/ | |||
public ProjectException( final String message ) | |||
{ | |||
super( message ); | |||
} | |||
/** | |||
* Constructs a cascaded exception. | |||
* | |||
* @param message The detail message for this exception. | |||
* @param throwable the root cause of the exception | |||
*/ | |||
public ProjectException( final String message, final Throwable throwable ) | |||
{ | |||
super( message, throwable ); | |||
} | |||
} |
@@ -1,41 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.classloader; | |||
import org.apache.myrmidon.interfaces.ComponentException; | |||
/** | |||
* An exception thrown by the ClassLoaderManager. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ClassLoaderException | |||
extends ComponentException | |||
{ | |||
/** | |||
* Constructs a non-cascaded exception. | |||
* | |||
* @param message The detail message for this exception. | |||
*/ | |||
public ClassLoaderException( final String message ) | |||
{ | |||
super( message ); | |||
} | |||
/** | |||
* Constructs a cascaded exception. | |||
* | |||
* @param message The detail message for this exception. | |||
* @param throwable the root cause of the exception | |||
*/ | |||
public ClassLoaderException( final String message, final Throwable throwable ) | |||
{ | |||
super( message, throwable ); | |||
} | |||
} |
@@ -1,55 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.classloader; | |||
import java.io.File; | |||
/** | |||
* Manages a classloader hierarchy. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface ClassLoaderManager | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = ClassLoaderManager.class.getName(); | |||
/** | |||
* Returns the ClassLoader for a Jar file. The ClassLoader is created, | |||
* if necessary. The ClassLoader's parent will include the common | |||
* ClassLoader, along with any extensions required by the Jar file. | |||
* It is guaranteed that each extension will appear at most once in the | |||
* ClassLoader hierarchy, so that classes from the extension can be | |||
* shared across the ClassLoaders returned by this method. | |||
* | |||
* @param jar the jar file containing the classes to load | |||
* @return the classloader | |||
* @throws ClassLoaderException on error | |||
*/ | |||
ClassLoader getClassLoader( File jar ) throws ClassLoaderException; | |||
/** | |||
* Creates a ClassLoader for a set of files. See {@link #getClassLoader} | |||
* for details. | |||
* | |||
* @param jars The Jar/zip files to create the classloader for. Use null | |||
* or an empty array to use the common classloader. | |||
* @return the created ClassLoader | |||
* @throws ClassLoaderException on error | |||
*/ | |||
ClassLoader createClassLoader( File[] jars ) throws ClassLoaderException; | |||
/** | |||
* Returns the common ClassLoader, which is the parent of all classloaders | |||
* built by this ClassLoaderManager. | |||
* | |||
* @return the common ClassLoader. | |||
*/ | |||
ClassLoader getCommonClassLoader(); | |||
} |
@@ -1,98 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.configurer; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.myrmidon.api.TaskContext; | |||
/** | |||
* Class used to configure tasks. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
* @ant:role shorthand="configurer" | |||
*/ | |||
public interface Configurer | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = Configurer.class.getName(); | |||
/** | |||
* Configure an object based on a configuration in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* @param object the object | |||
* @param configuration the configuration | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
void configureElement( Object object, Configuration configuration, TaskContext context ) | |||
throws ConfigurationException; | |||
/** | |||
* Configure named attribute of object in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* @param object the object | |||
* @param name the attribute name | |||
* @param value the attribute value | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
void configureAttribute( Object object, String name, String value, TaskContext context ) | |||
throws ConfigurationException; | |||
/** | |||
* Configure an object based on a configuration in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* The implementation of this method should only use the methods | |||
* specified by the supplied class. It is an error for the specified | |||
* class not to be a base class or interface compatible with specified | |||
* object. | |||
* | |||
* @param object the object | |||
* @param clazz the Class object to use during configuration | |||
* @param configuration the configuration | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
void configureElement( Object object, | |||
Class clazz, | |||
Configuration configuration, | |||
TaskContext context ) | |||
throws ConfigurationException; | |||
/** | |||
* Configure named attribute of object in a particular context. | |||
* This configuring can be done in different ways for different | |||
* configurers. | |||
* | |||
* The implementation of this method should only use the methods | |||
* specified by the supplied class. It is an error for the specified | |||
* class not to be a base class or interface compatible with specified | |||
* object. | |||
* | |||
* @param object the object | |||
* @param clazz the Class object to use during configuration | |||
* @param name the attribute name | |||
* @param value the attribute value | |||
* @param context the Context | |||
* @exception ConfigurationException if an error occurs | |||
*/ | |||
void configureAttribute( Object object, | |||
Class clazz, | |||
String name, | |||
String value, | |||
TaskContext context ) | |||
throws ConfigurationException; | |||
} |
@@ -1,29 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.converter; | |||
/** | |||
* Interface for registry for ConverterInfos. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface ConverterRegistry | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = ConverterRegistry.class.getName(); | |||
/** | |||
* Register a converter | |||
* | |||
* @param className the className of converter | |||
* @param source the source classname | |||
* @param destination the destination classname | |||
*/ | |||
void registerConverter( String className, String source, String destination ); | |||
} |
@@ -1,54 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.deployer; | |||
/** | |||
* A specialised TypeDefinition which defines a converter. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ConverterDefinition | |||
extends TypeDefinition | |||
{ | |||
private final String m_sourceType; | |||
private final String m_destinationType; | |||
/** | |||
* Creates a converter definition. | |||
* @param className the name of the implementing class | |||
* @param sourceType the name of the types converted from | |||
* @param destinationType the name of the type converted to | |||
*/ | |||
public ConverterDefinition( final String className, | |||
final String sourceType, | |||
final String destinationType ) | |||
{ | |||
super( className, "converter", className ); | |||
m_sourceType = sourceType; | |||
m_destinationType = destinationType; | |||
} | |||
/** | |||
* Provides the name of the type which this converter can convert from. | |||
* @return the converter's source type. | |||
*/ | |||
public String getSourceType() | |||
{ | |||
return m_sourceType; | |||
} | |||
/** | |||
* Provides the name of the type which this converter can convert to. | |||
* @return the converter's destination type. | |||
*/ | |||
public String getDestinationType() | |||
{ | |||
return m_destinationType; | |||
} | |||
} |
@@ -1,55 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.deployer; | |||
import java.io.File; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
/** | |||
* This class deploys type libraries into a registry. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface Deployer | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = Deployer.class.getName(); | |||
/** | |||
* Returns the deployer for the type libraries contained in a ClassLoader, | |||
* creating the deployer if necessary. | |||
* | |||
* @param loader The ClassLoader to get the deployer for. | |||
* @return the deployer for this loader. | |||
* @exception DeploymentException if an error occurs. | |||
*/ | |||
TypeDeployer createDeployer( ClassLoader loader ) | |||
throws DeploymentException; | |||
/** | |||
* Returns the deployer for a type library, creating the deployer if | |||
* necessary. | |||
* | |||
* @param file the file containing the type library. | |||
* @return the deployer for this type library. | |||
* @exception DeploymentException if an error occurs. | |||
*/ | |||
TypeDeployer createDeployer( File file ) | |||
throws DeploymentException; | |||
/** | |||
* Creates a deployer which is a child of this deployer. | |||
* @param componentManager the ServiceManager for this component. | |||
* @return a child deployer. | |||
* @throws ServiceException if an error occurs. | |||
*/ | |||
Deployer createChildDeployer( ServiceManager componentManager ) | |||
throws ServiceException; | |||
} |
@@ -1,41 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.deployer; | |||
import org.apache.myrmidon.interfaces.ComponentException; | |||
/** | |||
* Exception to indicate error deploying. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DeploymentException | |||
extends ComponentException | |||
{ | |||
/** | |||
* Constructs a non-cascaded exception. | |||
* | |||
* @param message The detail message for this exception. | |||
*/ | |||
public DeploymentException( final String message ) | |||
{ | |||
super( message ); | |||
} | |||
/** | |||
* Constructs a cascaded exception. | |||
* | |||
* @param message The detail message for this exception. | |||
* @param throwable the root cause of the exception | |||
*/ | |||
public DeploymentException( final String message, final Throwable throwable ) | |||
{ | |||
super( message, throwable ); | |||
} | |||
} |
@@ -1,60 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.deployer; | |||
/** | |||
* A general-purpose type definition. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TypeDefinition | |||
{ | |||
private final String m_name; | |||
private final String m_role; | |||
private final String m_classname; | |||
/** | |||
* Creates a TypeDefinition | |||
* @param name the name of the type | |||
* @param roleShorthand the name of the role played by this type | |||
* @param className the name of the class implementing this type | |||
*/ | |||
public TypeDefinition( final String name, | |||
final String roleShorthand, | |||
final String className ) | |||
{ | |||
m_name = name; | |||
m_role = roleShorthand; | |||
m_classname = className; | |||
} | |||
/** | |||
* @return the type's implementation class name. | |||
*/ | |||
public final String getClassname() | |||
{ | |||
return m_classname; | |||
} | |||
/** | |||
* @return the type's role. | |||
*/ | |||
public final String getRole() | |||
{ | |||
return m_role; | |||
} | |||
/** | |||
* @return the type's name. | |||
*/ | |||
public String getName() | |||
{ | |||
return m_name; | |||
} | |||
} |
@@ -1,54 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.deployer; | |||
/** | |||
* A deployer for a type library. Allows individual elements from a type | |||
* library to be deployed. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface TypeDeployer | |||
{ | |||
/** | |||
* Deploys everything in the type library. | |||
* @throws DeploymentException | |||
* If the library cannot be deployed. | |||
*/ | |||
void deployAll() | |||
throws DeploymentException; | |||
/** | |||
* Deploys a single type from the type library. The type definition is | |||
* read from the type library descriptor. | |||
* | |||
* @param roleShorthand | |||
* The shorthand name for the role. | |||
* | |||
* @param typeName | |||
* The type name. | |||
* | |||
* @throws DeploymentException | |||
* If the type cannot be deployed. | |||
*/ | |||
void deployType( String roleShorthand, String typeName ) | |||
throws DeploymentException; | |||
/** | |||
* Deploys a single type from the type library. | |||
* | |||
* @param typeDef | |||
* The type definition. | |||
* | |||
* @throws DeploymentException | |||
* If the type cannot be deployed. | |||
*/ | |||
void deployType( TypeDefinition typeDef ) | |||
throws DeploymentException; | |||
} |
@@ -1,65 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.embeddor; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||
import org.apache.myrmidon.listeners.ProjectListener; | |||
import java.util.Map; | |||
/** | |||
* Interface through which you embed Myrmidon into applications. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface Embeddor | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = Embeddor.class.getName(); | |||
/** | |||
* Creates a project from a project file. | |||
* | |||
* @param location The path to the project file. | |||
* @param type The project file type. If null the type is inferred from the | |||
* project file name. | |||
* @param parameters The project builder parameters. | |||
* @return the created Project | |||
* @throws Exception If an error occurs creating the Project. | |||
* | |||
* @todo Should location be a URL or will it automatically assume file | |||
* unless there is a protocol section like ftp:, file: etc | |||
* @todo parameters needs more thought put into it. | |||
*/ | |||
Project createProject( String location, String type, Parameters parameters ) | |||
throws Exception; | |||
/** | |||
* Creates a project listener. | |||
* | |||
* @param name The shorthand name of the listener. | |||
* @return the listener. | |||
* @throws Exception If the listener could not be created. | |||
*/ | |||
ProjectListener createListener( String name ) | |||
throws Exception; | |||
/** | |||
* Creates a {@link Workspace} that can be used to execute projects. | |||
* | |||
* @param properties The properties to define in the workspace. These | |||
* are added to the properties in the embeddor's | |||
* root execution frame. | |||
* @return the Workspace | |||
* @throws Exception If the workspace could not be created. | |||
*/ | |||
Workspace createWorkspace( Map properties ) | |||
throws Exception; | |||
} |
@@ -1,23 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.executor; | |||
/** | |||
* This interface is used to supply a root execution frame to a container | |||
* that executes tasks. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface ExecutionContainer | |||
{ | |||
/** | |||
* Sets the root execution frame for the container. | |||
*/ | |||
void setRootExecutionFrame( ExecutionFrame frame ) throws Exception; | |||
} |
@@ -1,46 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.executor; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.myrmidon.interfaces.property.PropertyStore; | |||
/** | |||
* An Execution Frame represents the scope in which tasks are executed. | |||
* The scope may include an entire workspace, a project, target, or | |||
* individual task. | |||
* | |||
* <p>An Execution Frame bundles together all of the context required to | |||
* execute tasks - that is, a set of properties, a set of services, and | |||
* a logger. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface ExecutionFrame | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = ExecutionFrame.class.getName(); | |||
/** | |||
* Returns the set of services to use to create, configure, and execute | |||
* tasks. | |||
*/ | |||
ServiceManager getServiceManager(); | |||
/** | |||
* Returns the logger which is to be supplied to tasks. | |||
*/ | |||
Logger getLogger(); | |||
/** | |||
* Returns the set of properties to be supplied to tasks. | |||
*/ | |||
PropertyStore getProperties(); | |||
} |
@@ -1,33 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.executor; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
* Engine inteface that should be implemented by all tasklet engines. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface Executor | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = Executor.class.getName(); | |||
/** | |||
* execute a task. | |||
* | |||
* @param task the configruation data for task | |||
* @param frame The frame in which the task is executed. | |||
* @exception TaskException if an error occurs | |||
*/ | |||
void execute( Configuration task, ExecutionFrame frame ) | |||
throws TaskException; | |||
} |
@@ -1,31 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.extensions; | |||
import org.apache.avalon.excalibur.extension.Extension; | |||
import org.apache.avalon.excalibur.extension.OptionalPackage; | |||
/** | |||
* Maintains a set of optional packages. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface ExtensionManager | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = ExtensionManager.class.getName(); | |||
/** | |||
* Locates the optional package which best matches a required extension. | |||
* | |||
* @param extension the extension to locate an optional package | |||
* @return the optional package, or null if not found. | |||
*/ | |||
OptionalPackage getOptionalPackage( Extension extension ); | |||
} |
@@ -1,356 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.model; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
/** | |||
* Simple helper class which determines the validity of names used | |||
* in ant projects. | |||
* | |||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultNameValidator | |||
implements NameValidator | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( DefaultNameValidator.class ); | |||
/** | |||
* Determines whether the supplied name may include surrounding whitespace. | |||
*/ | |||
private boolean m_allowSurroundingWhitespace; | |||
// Settings for initial characters. | |||
private boolean m_allowInitialDigit; | |||
private String m_additionalInitialCharacters; | |||
// Settings for internal characters. | |||
private boolean m_allowInternalDigits; | |||
private boolean m_allowInternalWhitespace; | |||
private String m_additionalInternalCharacters; | |||
/** | |||
* Construct a default name validator. | |||
* Letters, digits and "_" are permitted as initial character. | |||
* Letters, digits, whitespace and "_-." are permitted as internal characters. | |||
* Surrounding whitespace is not permitted. | |||
*/ | |||
public DefaultNameValidator() | |||
{ | |||
this( false, true, "_", true, true, "_-." ); | |||
} | |||
/** | |||
* Contstruct a NameValidator with the specified rules. | |||
* @param allowSurroundingWhitespace | |||
* specified if names are trimmed before checking | |||
* @param allowInitialDigit | |||
* specifies if digits are permitted as intial characters | |||
* @param additionalInitialCharacters | |||
* extra characters to allow as initial characters. | |||
* @param allowInternalDigits | |||
* specifies if digits are permitted as internal characters | |||
* @param allowInternalWhitespace | |||
* specifies if whitespace is permitted internally in names | |||
* @param additionalInternalCharacters | |||
* extra characters permitted in names | |||
*/ | |||
public DefaultNameValidator( final boolean allowSurroundingWhitespace, | |||
final boolean allowInitialDigit, | |||
final String additionalInitialCharacters, | |||
final boolean allowInternalDigits, | |||
final boolean allowInternalWhitespace, | |||
final String additionalInternalCharacters ) | |||
{ | |||
setAllowSurroundingWhitespace( allowSurroundingWhitespace ); | |||
setAllowInitialDigit( allowInitialDigit ); | |||
setAdditionalInitialCharacters( additionalInitialCharacters ); | |||
setAllowInternalDigits( allowInternalDigits ); | |||
setAllowInternalWhitespace( allowInternalWhitespace ); | |||
setAdditionalInternalCharacters( additionalInternalCharacters ); | |||
} | |||
/** | |||
* Creates a valid name based on the supplied string value, removing invalid | |||
* characters. If no valid characters are present, an exception is thrown. | |||
* @param baseName the name used to construct the valid name | |||
* @return a valid name based on the supplied name. | |||
* @throws Exception if no valid name could be constructed. | |||
*/ | |||
public String makeValidName( final String baseName ) throws Exception | |||
{ | |||
final StringBuffer buffer = new StringBuffer( baseName ); | |||
while( buffer.length() > 0 && !isValidInitialChar( buffer.charAt( 0 ) ) ) | |||
{ | |||
buffer.delete( 0, 1 ); | |||
} | |||
if( buffer.length() == 0 ) | |||
{ | |||
final String message = REZ.getString( "name.could-not-create.error", baseName ); | |||
throw new Exception( message ); | |||
} | |||
for( int i = 1; i < buffer.length(); ) | |||
{ | |||
if( !isValidInternalChar( buffer.charAt( i ) ) ) | |||
{ | |||
buffer.delete( i, i + 1 ); | |||
} | |||
else | |||
{ | |||
i++; | |||
} | |||
} | |||
return buffer.toString(); | |||
} | |||
/** | |||
* @see NameValidator | |||
*/ | |||
public void validate( final String name ) throws Exception | |||
{ | |||
String testName = name; | |||
// If surrounding whitespace is allowed, trim it. Otherwise, check. | |||
if( m_allowSurroundingWhitespace ) | |||
{ | |||
testName = testName.trim(); | |||
} | |||
else | |||
{ | |||
checkSurroundingWhitespace( testName ); | |||
} | |||
// Zero-length name is invalid. | |||
if( testName.length() == 0 ) | |||
{ | |||
final String message = REZ.getString( "name.zero-char-name.error" ); | |||
throw new Exception( message ); | |||
} | |||
// Check first character. | |||
final char initial = testName.charAt( 0 ); | |||
checkInitialCharacter( initial, testName ); | |||
// Check the rest of the characters. | |||
for( int i = 1; i < testName.length(); i++ ) | |||
{ | |||
final char internal = testName.charAt( i ); | |||
checkInternalCharacter( internal, testName ); | |||
} | |||
} | |||
/** | |||
* Checks if the supplied character is permitted as an internal character. | |||
* @throws Exception if the character is not permitted | |||
*/ | |||
private void checkInternalCharacter( final char internal, final String name ) | |||
throws Exception | |||
{ | |||
if( !isValidInternalChar( internal ) ) | |||
{ | |||
final String message = REZ.getString( "name.invalid-internal-char.error", | |||
name, | |||
describeValidInternalChars() ); | |||
throw new Exception( message ); | |||
} | |||
} | |||
/** | |||
* Checks if the supplied character is permitted as an internal character. | |||
* @throws Exception if the character is not permitted | |||
*/ | |||
private void checkInitialCharacter( final char initial, final String name ) | |||
throws Exception | |||
{ | |||
if( !isValidInitialChar( initial ) ) | |||
{ | |||
final String message = REZ.getString( "name.invalid-initial-char.error", | |||
name, | |||
describeValidInitialChars() ); | |||
throw new Exception( message ); | |||
} | |||
} | |||
/** | |||
* Checks the name for surrounding whitespace | |||
* @throws Exception if surrounding whitespace is found | |||
*/ | |||
private void checkSurroundingWhitespace( final String testName ) | |||
throws Exception | |||
{ | |||
if( testName.length() == 0 ) | |||
{ | |||
return; | |||
} | |||
if( Character.isWhitespace( testName.charAt( 0 ) ) || | |||
Character.isWhitespace( testName.charAt( testName.length() - 1 ) ) ) | |||
{ | |||
final String message = | |||
REZ.getString( "name.enclosing-whitespace.error", testName ); | |||
throw new Exception( message ); | |||
} | |||
} | |||
/** | |||
* Determines if a character is allowed as the first character in a name. | |||
* Valid characters are Letters, Digits, and defined initial characters ("_"). | |||
* @param chr the character to be assessed | |||
* @return <code>true</code> if the character can be the first character of a name | |||
*/ | |||
protected boolean isValidInitialChar( final char chr ) | |||
{ | |||
if( Character.isLetter( chr ) ) | |||
{ | |||
return true; | |||
} | |||
if( m_allowInitialDigit | |||
&& Character.isDigit( chr ) ) | |||
{ | |||
return true; | |||
} | |||
if( m_additionalInitialCharacters.indexOf( chr ) != -1 ) | |||
{ | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Determines if a character is allowed as a non-initial character in a name. | |||
* Valid characters are Letters, Digits, whitespace, and defined | |||
* internal characters ("_-."). | |||
* @param chr the character to be assessed | |||
* @return <code>true</code> if the character can be included in a name | |||
*/ | |||
protected boolean isValidInternalChar( final char chr ) | |||
{ | |||
if( Character.isLetter( chr ) ) | |||
{ | |||
return true; | |||
} | |||
if( m_allowInternalDigits | |||
&& Character.isDigit( chr ) ) | |||
{ | |||
return true; | |||
} | |||
if( m_allowInternalWhitespace | |||
&& Character.isWhitespace( chr ) ) | |||
{ | |||
return true; | |||
} | |||
if( m_additionalInternalCharacters.indexOf( chr ) != -1 ) | |||
{ | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Builds a message detailing the valid initial characters. | |||
*/ | |||
protected String describeValidInitialChars() | |||
{ | |||
StringBuffer validChars = new StringBuffer( "letters" ); | |||
if( m_allowInitialDigit ) | |||
{ | |||
validChars.append( ", digits" ); | |||
} | |||
validChars.append( ", and \"" ); | |||
validChars.append( m_additionalInitialCharacters ); | |||
validChars.append( "\"" ); | |||
return validChars.toString(); | |||
} | |||
/** | |||
* Builds a message detailing the valid internal characters. | |||
*/ | |||
protected String describeValidInternalChars() | |||
{ | |||
StringBuffer validChars = new StringBuffer( "letters" ); | |||
if( m_allowInternalDigits ) | |||
{ | |||
validChars.append( ", digits" ); | |||
} | |||
if( m_allowInternalWhitespace ) | |||
{ | |||
validChars.append( ", whitespace" ); | |||
} | |||
validChars.append( ", and \"" ); | |||
validChars.append( m_additionalInternalCharacters ); | |||
validChars.append( "\"" ); | |||
return validChars.toString(); | |||
} | |||
/** | |||
* @param allowSurroundingWhitespace | |||
* specified if names are trimmed before checking | |||
*/ | |||
public void setAllowSurroundingWhitespace( boolean allowSurroundingWhitespace ) | |||
{ | |||
m_allowSurroundingWhitespace = allowSurroundingWhitespace; | |||
} | |||
/** | |||
* @param allowInitialDigit | |||
* specifies if digits are permitted as intial characters | |||
*/ | |||
public void setAllowInitialDigit( boolean allowInitialDigit ) | |||
{ | |||
m_allowInitialDigit = allowInitialDigit; | |||
} | |||
/** | |||
* @param additionalInitialCharacters | |||
* extra characters to allow as initial characters. | |||
*/ | |||
public void setAdditionalInitialCharacters( String additionalInitialCharacters ) | |||
{ | |||
m_additionalInitialCharacters = additionalInitialCharacters; | |||
} | |||
/** | |||
* @param allowInternalDigits | |||
* specifies if digits are permitted as internal characters | |||
*/ | |||
public void setAllowInternalDigits( boolean allowInternalDigits ) | |||
{ | |||
m_allowInternalDigits = allowInternalDigits; | |||
} | |||
/** | |||
* @param allowInternalWhitespace | |||
* specifies if whitespace is permitted internally in names | |||
*/ | |||
public void setAllowInternalWhitespace( boolean allowInternalWhitespace ) | |||
{ | |||
m_allowInternalWhitespace = allowInternalWhitespace; | |||
} | |||
/** | |||
* @param additionalInternalCharacters | |||
* extra characters permitted in names | |||
*/ | |||
public void setAdditionalInternalCharacters( String additionalInternalCharacters ) | |||
{ | |||
m_additionalInternalCharacters = additionalInternalCharacters; | |||
} | |||
} |
@@ -1,46 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.model; | |||
/** | |||
* A dependency for a target. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class Dependency | |||
{ | |||
private final String m_projectName; | |||
private final String m_targetName; | |||
/** | |||
* @param projectName The project containing the depended-on target. | |||
* @param targetName The name of the depended-on target. | |||
*/ | |||
public Dependency( final String projectName, final String targetName ) | |||
{ | |||
m_projectName = projectName; | |||
m_targetName = targetName; | |||
} | |||
/** | |||
* @return The name of the project containing the depended-on target. | |||
*/ | |||
public String getProjectName() | |||
{ | |||
return m_projectName; | |||
} | |||
/** | |||
* @return The name of the depended-on target. | |||
*/ | |||
public String getTargetName() | |||
{ | |||
return m_targetName; | |||
} | |||
} |
@@ -1,26 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.model; | |||
/** | |||
* Determines the validity of names used in projects. | |||
* | |||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface NameValidator | |||
{ | |||
/** | |||
* Validates the supplied name, failing if it is not. | |||
* | |||
* @param name The name to be validated. | |||
* @throws Exception is the supplied name is not valid. | |||
*/ | |||
void validate( String name ) | |||
throws Exception; | |||
} |
@@ -1,100 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.model; | |||
import java.io.File; | |||
/** | |||
* Abstraction used to interact with projects. | |||
* Implementations may choose to structure it anyway they choose. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface Project | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = Project.class.getName(); | |||
/** Property which holds the name of currently executing project */ | |||
String PROJECT = "myrmidon.project.name"; | |||
// the name of currently executing project | |||
//String PROJECT_FILE = "myrmidon.project.file"; | |||
// the name of currently executing target | |||
//String TARGET = "myrmidon.target.name"; | |||
/** | |||
* @return the project name. | |||
* | |||
* TODO: Determine if projects should carry their own name. Breaks IOC but | |||
* Can be useful as project files embed own name (or should that be description). | |||
*/ | |||
String getProjectName(); | |||
/** | |||
* Get the imports for project. | |||
* | |||
* @return the imports | |||
*/ | |||
TypeLib[] getTypeLibs(); | |||
/** | |||
* Get names of projects referenced by this project. | |||
* | |||
* @return the names | |||
*/ | |||
String[] getProjectNames(); | |||
/** | |||
* Retrieve project referenced by this project. | |||
* | |||
* @param name the project name | |||
* @return the Project or null if none by that name | |||
*/ | |||
Project getProject( String name ); | |||
/** | |||
* Get name of default target. | |||
* | |||
* @return the default target name | |||
*/ | |||
String getDefaultTargetName(); | |||
/** | |||
* Retrieve implicit target. | |||
* The implicit target is top level tasks. | |||
* Currently restricted to property tasks. | |||
* | |||
* @return the Target | |||
*/ | |||
Target getImplicitTarget(); | |||
/** | |||
* Retrieve a target by name. | |||
* | |||
* @param name the name of target | |||
* @return the Target or null if no target exists with name | |||
*/ | |||
Target getTarget( String name ); | |||
/** | |||
* Retrieve names of all targets in project. | |||
* | |||
* @return the iterator of project names | |||
*/ | |||
String[] getTargetNames(); | |||
/** | |||
* Retrieve base directory of project. | |||
* | |||
* @return the projects base directory | |||
*/ | |||
File getBaseDirectory(); | |||
} |
@@ -1,6 +0,0 @@ | |||
# Name validation | |||
name.zero-char-name.error=Name "" is invalid, as it contains no characters. | |||
name.enclosing-whitespace.error=Name "{0}" is invalid, as it contains enclosing whitespace. | |||
name.invalid-initial-char.error=Name "{0}" is invalid, as it begins with an illegal character. Names can start with {1}. | |||
name.invalid-internal-char.error=Name "{0}" is invalid, as it contains an illegal character. Permitted name characters are {1}. | |||
name.could-not-create.error=Could not valid name from "{0}". |
@@ -1,65 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.model; | |||
import java.util.ArrayList; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
/** | |||
* Targets in build file. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class Target | |||
{ | |||
private final ArrayList m_dependencies = new ArrayList(); | |||
private final ArrayList m_tasks = new ArrayList(); | |||
/** | |||
* Constructs a target. | |||
* @param tasks The task models for all tasks in this target. | |||
* @param dependencies The dependencies for executing this target. | |||
*/ | |||
public Target( final Configuration[] tasks, | |||
final Dependency[] dependencies ) | |||
{ | |||
for( int i = 0; i < tasks.length; i++ ) | |||
{ | |||
m_tasks.add( tasks[ i ] ); | |||
} | |||
if( null != dependencies ) | |||
{ | |||
for( int i = 0; i < dependencies.length; i++ ) | |||
{ | |||
m_dependencies.add( dependencies[ i ] ); | |||
} | |||
} | |||
} | |||
/** | |||
* Get dependencies of target | |||
* | |||
* @return the dependency list | |||
*/ | |||
public final Dependency[] getDependencies() | |||
{ | |||
return (Dependency[])m_dependencies.toArray( new Dependency[ 0 ] ); | |||
} | |||
/** | |||
* Get tasks in target | |||
* | |||
* @return the target list | |||
*/ | |||
public final Configuration[] getTasks() | |||
{ | |||
return (Configuration[])m_tasks.toArray( new Configuration[ 0 ] ); | |||
} | |||
} |
@@ -1,93 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.model; | |||
/** | |||
* Imports in a build file. | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TypeLib | |||
{ | |||
//Name of library (this is location independent) | |||
private final String m_library; | |||
//Do we need this?? | |||
//private final String m_namespace; | |||
//The role of object to be imported | |||
private final String m_role; | |||
//The name of type instance | |||
private final String m_name; | |||
/** | |||
* Create a import for a complete library. | |||
* @param library The name of the library to import. | |||
*/ | |||
public TypeLib( final String library ) | |||
{ | |||
this( library, null, null ); | |||
} | |||
/** | |||
* Create an import for a single type from a library. | |||
* @param library The library containing the type. | |||
* @param role The role for the imported type. | |||
* @param name The name of the imported type. | |||
*/ | |||
public TypeLib( final String library, final String role, final String name ) | |||
{ | |||
m_library = library; | |||
m_role = role; | |||
m_name = name; | |||
//If only one of name or type is null, throw an exception | |||
if( null == m_role || null == m_name ) | |||
{ | |||
if( null != m_role || null != m_name ) | |||
{ | |||
throw new IllegalArgumentException( "Can not have an import that specifies " + | |||
"only one of; name or role" ); | |||
} | |||
} | |||
} | |||
/** | |||
* Get role | |||
* | |||
* @return the role | |||
*/ | |||
public final String getRole() | |||
{ | |||
return m_role; | |||
} | |||
/** | |||
* Get name of imported | |||
* | |||
* @return the name | |||
*/ | |||
public final String getName() | |||
{ | |||
return m_name; | |||
} | |||
/** | |||
* Get name of library | |||
* | |||
* @return the library name | |||
*/ | |||
public final String getLibrary() | |||
{ | |||
return m_library; | |||
} | |||
} | |||
@@ -1,119 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.property; | |||
import java.util.Map; | |||
import java.util.HashMap; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
/** | |||
* A simple unscoped, unsynchronized property store which is backed by a Map. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class MapPropertyStore | |||
implements PropertyStore | |||
{ | |||
private static final Resources REZ = | |||
ResourceManager.getPackageResources( MapPropertyStore.class ); | |||
private final Map m_properties = new HashMap(); | |||
/** | |||
* Creates an empty store. | |||
*/ | |||
public MapPropertyStore() | |||
{ | |||
} | |||
/** | |||
* Creates a store containing the given properties. | |||
*/ | |||
public MapPropertyStore( final Map properties ) | |||
{ | |||
m_properties.putAll( properties ); | |||
} | |||
/** | |||
* Return <code>true</code> if the specified property is set. | |||
* | |||
* @param name the name of property | |||
*/ | |||
public boolean isPropertySet( final String name ) | |||
{ | |||
return m_properties.containsKey( name ); | |||
} | |||
/** | |||
* Retrieve the value of specified property. | |||
* | |||
* @param name the name of the property | |||
* @return the value of the property. Never returns null. | |||
* @throws TaskException if there is no such property, or on error | |||
* retrieving property, such as an invalid property name. | |||
*/ | |||
public Object getProperty( final String name ) | |||
throws TaskException | |||
{ | |||
final Object value = m_properties.get( name ); | |||
if( value == null ) | |||
{ | |||
final String message = REZ.getString( "unknown-property.error", name ); | |||
throw new TaskException( message ); | |||
} | |||
return value; | |||
} | |||
/** | |||
* Retrieve a copy of all the properties that are "in-scope" | |||
* for store. | |||
* | |||
* @return a copy of all the properties that are "in-scope" | |||
* for store. | |||
* @throws TaskException if theres an error retrieving propertys | |||
*/ | |||
public Map getProperties() | |||
throws TaskException | |||
{ | |||
return new HashMap( m_properties ); | |||
} | |||
/** | |||
* Set the property with specified name to specified value. | |||
* The specific implementation will apply various rules | |||
* before setting the property. | |||
* | |||
* @param name the name of property | |||
* @param value the value of property | |||
* @throws TaskException if property can not be set | |||
*/ | |||
public void setProperty( String name, Object value ) | |||
throws TaskException | |||
{ | |||
m_properties.put( name, value ); | |||
} | |||
/** | |||
* Return a child PropertyStore with specified name. | |||
* This is to allow support for scoped stores. However a | |||
* store may choose to be unscoped and just return a | |||
* reference to itself. | |||
* | |||
* @param name the name of child store | |||
* @return the child store | |||
* @throws TaskException if theres an error creating child store | |||
*/ | |||
public PropertyStore createChildStore( String name ) | |||
throws TaskException | |||
{ | |||
return this; | |||
} | |||
} |
@@ -1,41 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.property; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.api.TaskContext; | |||
/** | |||
* | |||
* Provides a service for the resolution of property identifiers within | |||
* String content. | |||
* | |||
* @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
* @version $Revision$ $Date$ | |||
* | |||
* @ant:role shorthand="property-resolver" | |||
*/ | |||
public interface PropertyResolver | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = PropertyResolver.class.getName(); | |||
/** | |||
* Resolve a string property. This evaluates all property | |||
* substitutions based on specified contex. | |||
* Rules used for property resolution are implementation dependent. | |||
* | |||
* @param value the value to resolve, which may contain property identifiers | |||
* @param context the set of properties to resolve against. | |||
* @return the resolved content | |||
* @exception TaskException if an error occurs | |||
*/ | |||
Object resolveProperties( final String value, | |||
final TaskContext context ) | |||
throws TaskException; | |||
} |
@@ -1,86 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.property; | |||
import java.util.Map; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
* This component stores and manages properties. It is also | |||
* responsible for instituting the various policies regarding | |||
* propertys. ie It will enforce rules regarding | |||
* | |||
* <ul> | |||
* <li>Valid property names?</li> | |||
* <li>Are propertys mutable?</li> | |||
* <li>Are propertys scoped?</li> | |||
* <li>Is mapping between name and value correct?</li> | |||
* </ul> | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface PropertyStore | |||
{ | |||
/** Role name for this interface. */ | |||
String ROLE = PropertyStore.class.getName(); | |||
/** | |||
* Set the property with specified name to specified value. | |||
* The specific implementation will apply various rules | |||
* before setting the property. | |||
* | |||
* @param name the name of property | |||
* @param value the value of property | |||
* @throws TaskException if property can not be set | |||
*/ | |||
void setProperty( String name, Object value ) | |||
throws TaskException; | |||
/** | |||
* Return <code>true</code> if the specified property is set. | |||
* | |||
* @param name the name of property | |||
*/ | |||
boolean isPropertySet( String name ); | |||
/** | |||
* Retrieve the value of specified property. | |||
* | |||
* @param name the name of the property | |||
* @return the value of the property. Never returns null. | |||
* @throws TaskException if there is no such property, or on error | |||
* retrieving property, such as an invalid property name. | |||
*/ | |||
Object getProperty( String name ) | |||
throws TaskException; | |||
/** | |||
* Retrieve a copy of all the properties that are "in-scope" | |||
* for store. | |||
* | |||
* @return a copy of all the properties that are "in-scope" | |||
* for store. | |||
* @throws TaskException if theres an error retrieving propertys | |||
*/ | |||
Map getProperties() | |||
throws TaskException; | |||
/** | |||
* Return a child PropertyStore with specified name. | |||
* This is to allow support for scoped stores. However a | |||
* store may choose to be unscoped and just return a | |||
* reference to itself. | |||
* | |||
* @param name the name of child store | |||
* @return the child store | |||
* @throws TaskException if theres an error creating child store | |||
*/ | |||
PropertyStore createChildStore( String name ) | |||
throws TaskException; | |||
} |