* Removed "if" and "unless" conditions from targets. * Moved parsing of "project->target" dependencies out of DefaultWorkspace, into DefaultProjectBuilder. * DefaultWorkspace now detects cycles in the target dependency graph. * DefaultWorkspace now executes the implicit target for referenced projects. * Changes to DefaultProjectBuilder error reporting. * Added a few more test cases for DefaultProjectBuilder. Unit Tests: * Moved AbstractComponentTest.getLogger() up to AbstractMyrmidonTest. * Removed AbstractComponentTest.setup(). Components are now created on demand. * Use BasicLogger in unit tests. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271835 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -0,0 +1,3 @@ | |||
| <!-- Project with invalid version --> | |||
| <project version="ant2"> | |||
| </project> | |||
| @@ -0,0 +1 @@ | |||
| this ain't xml. | |||
| @@ -0,0 +1,3 @@ | |||
| <!-- Use all the defaults --> | |||
| <project version="2.0"> | |||
| </project> | |||
| @@ -0,0 +1,3 @@ | |||
| <!-- Project with mismatched version --> | |||
| <project version="1.0.2"> | |||
| </project> | |||
| @@ -0,0 +1,3 @@ | |||
| <!-- Project with no version attribute --> | |||
| <project> | |||
| </project> | |||
| @@ -0,0 +1,3 @@ | |||
| <!-- Project with a non-default base directory --> | |||
| <project version="2.0" basedir="other-base-dir"> | |||
| </project> | |||
| @@ -0,0 +1,3 @@ | |||
| <!-- Project with a non-default default target --> | |||
| <project version="2.0" default="some-target"> | |||
| </project> | |||
| @@ -0,0 +1,3 @@ | |||
| <!-- Project with non-default name --> | |||
| <project name="some-project" version="2.0"> | |||
| </project > | |||
| @@ -8,8 +8,6 @@ | |||
| package org.apache.myrmidon.components.builder; | |||
| import java.io.File; | |||
| import java.net.MalformedURLException; | |||
| import java.net.URL; | |||
| import java.util.ArrayList; | |||
| import java.util.HashMap; | |||
| import javax.xml.parsers.SAXParser; | |||
| @@ -23,13 +21,10 @@ 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.framework.conditions.AndCondition; | |||
| import org.apache.myrmidon.framework.conditions.Condition; | |||
| import org.apache.myrmidon.framework.conditions.IsSetCondition; | |||
| import org.apache.myrmidon.framework.conditions.NotCondition; | |||
| 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; | |||
| @@ -78,31 +73,39 @@ public class DefaultProjectBuilder | |||
| private Project build( final File file, final HashMap projects ) | |||
| throws ProjectException | |||
| { | |||
| final URL systemID = extractURL( file ); | |||
| final Project result = (Project)projects.get( systemID.toString() ); | |||
| if( null != result ) | |||
| try | |||
| { | |||
| return result; | |||
| } | |||
| // Parse the project file | |||
| final Configuration configuration = parseProject( systemID ); | |||
| // Check for cached project | |||
| final String systemID = extractURL( file ); | |||
| final Project result = (Project)projects.get( systemID ); | |||
| if( null != result ) | |||
| { | |||
| return result; | |||
| } | |||
| // Build the project model | |||
| final DefaultProject project = buildProject( file, configuration ); | |||
| // Parse the project file | |||
| final Configuration configuration = parseProject( systemID ); | |||
| projects.put( systemID.toString(), project ); | |||
| // 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 ); | |||
| // Build using all top-level attributes | |||
| buildTopLevelProject( project, configuration, projects ); | |||
| return project; | |||
| return project; | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| final String message = REZ.getString( "ant.project-build.error", file.getAbsolutePath() ); | |||
| throw new ProjectException( message, e ); | |||
| } | |||
| } | |||
| /** | |||
| * Parses the project. | |||
| */ | |||
| private Configuration parseProject( final URL systemID ) | |||
| private Configuration parseProject( final String systemID ) | |||
| throws ProjectException | |||
| { | |||
| try | |||
| @@ -117,13 +120,13 @@ public class DefaultProjectBuilder | |||
| parser.setContentHandler( handler ); | |||
| parser.setErrorHandler( handler ); | |||
| parser.parse( systemID.toString() ); | |||
| parser.parse( systemID ); | |||
| return handler.getConfiguration(); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| String message = REZ.getString( "ant.project-parse.error" ); | |||
| final String message = REZ.getString( "ant.project-parse.error" ); | |||
| throw new ProjectException( message, e ); | |||
| } | |||
| } | |||
| @@ -164,7 +167,7 @@ public class DefaultProjectBuilder | |||
| File baseDirectory = file.getParentFile(); | |||
| if( baseDirectoryName != null ) | |||
| { | |||
| baseDirectory = new File( baseDirectory, baseDirectoryName ); | |||
| baseDirectory = FileUtil.resolveFile( baseDirectory, baseDirectoryName ); | |||
| } | |||
| baseDirectory = baseDirectory.getAbsoluteFile(); | |||
| @@ -257,7 +260,7 @@ public class DefaultProjectBuilder | |||
| { | |||
| final String message = | |||
| REZ.getString( "ant.malformed.version", versionString ); | |||
| throw new ProjectException( message, e ); | |||
| throw new ProjectException( message ); | |||
| } | |||
| } | |||
| @@ -338,7 +341,7 @@ public class DefaultProjectBuilder | |||
| final Configuration[] implicitTasks = | |||
| (Configuration[])implicitTaskList.toArray( new Configuration[ 0 ] ); | |||
| final Target implicitTarget = new Target( null, implicitTasks, null ); | |||
| final Target implicitTarget = new Target( implicitTasks, null ); | |||
| project.setImplicitTarget( implicitTarget ); | |||
| } | |||
| @@ -378,26 +381,30 @@ public class DefaultProjectBuilder | |||
| // Build the URL of the referenced projects | |||
| final File baseDirectory = project.getBaseDirectory(); | |||
| final File file = FileUtil.resolveFile( baseDirectory, location ); | |||
| final String systemID = extractURL( file ).toString(); | |||
| // Locate the referenced project, building it if necessary | |||
| Project other = (Project)projects.get( systemID ); | |||
| if( null == other ) | |||
| { | |||
| other = build( file, projects ); | |||
| } | |||
| final Project other = build( file, projects ); | |||
| // Add the reference | |||
| project.addProject( name, other ); | |||
| } | |||
| private URL extractURL( final File file ) throws ProjectException | |||
| /** | |||
| * 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.toURL(); | |||
| return file.getCanonicalFile().toURL().toString(); | |||
| } | |||
| catch( MalformedURLException e ) | |||
| catch( Exception e ) | |||
| { | |||
| final String message = REZ.getString( "ant.project-unexpected.error" ); | |||
| throw new ProjectException( message, e ); | |||
| @@ -443,8 +450,6 @@ public class DefaultProjectBuilder | |||
| { | |||
| final String name = target.getAttribute( "name", null ); | |||
| final String depends = target.getAttribute( "depends", null ); | |||
| final String ifCondition = target.getAttribute( "if", null ); | |||
| final String unlessCondition = target.getAttribute( "unless", null ); | |||
| verifyTargetName( name, target ); | |||
| @@ -454,10 +459,8 @@ public class DefaultProjectBuilder | |||
| getLogger().debug( message ); | |||
| } | |||
| final String[] dependencies = buildDependsList( depends, target ); | |||
| final Condition condition = buildCondition( ifCondition, unlessCondition ); | |||
| final Target defaultTarget = | |||
| new Target( condition, target.getChildren(), dependencies ); | |||
| final Dependency[] dependencies = buildDependsList( depends, target ); | |||
| final Target defaultTarget = new Target( target.getChildren(), dependencies ); | |||
| //add target to project | |||
| project.addTarget( name, defaultTarget ); | |||
| @@ -485,70 +488,54 @@ public class DefaultProjectBuilder | |||
| } | |||
| } | |||
| private String[] buildDependsList( final String depends, final Configuration target ) | |||
| private Dependency[] buildDependsList( final String depends, final Configuration target ) | |||
| throws ProjectException | |||
| { | |||
| String[] dependencies = null; | |||
| //apply depends attribute | |||
| if( null != depends ) | |||
| if( null == depends ) | |||
| { | |||
| 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( 0 == dependency.length() ) | |||
| { | |||
| final String message = REZ.getString( "ant.target-bad-dependency.error", | |||
| target.getName(), | |||
| target.getLocation() ); | |||
| throw new ProjectException( message ); | |||
| } | |||
| if( getLogger().isDebugEnabled() ) | |||
| { | |||
| final String message = REZ.getString( "ant.target-dependency.notice", dependency ); | |||
| getLogger().debug( message ); | |||
| } | |||
| dependsList.add( dependency ); | |||
| } | |||
| dependencies = (String[])dependsList.toArray( new String[ 0 ] ); | |||
| return null; | |||
| } | |||
| return dependencies; | |||
| } | |||
| private Condition buildCondition( final String ifCondition, | |||
| final String unlessCondition ) | |||
| { | |||
| final AndCondition condition = new AndCondition(); | |||
| final String[] elements = StringUtil.split( depends, "," ); | |||
| final ArrayList dependsList = new ArrayList(); | |||
| // Add the 'if' condition | |||
| if( null != ifCondition ) | |||
| for( int i = 0; i < elements.length; i++ ) | |||
| { | |||
| final String dependency = elements[ i ].trim(); | |||
| if( getLogger().isDebugEnabled() ) | |||
| { | |||
| final String message = REZ.getString( "ant.target-if.notice", ifCondition ); | |||
| final String message = REZ.getString( "ant.target-dependency.notice", dependency ); | |||
| getLogger().debug( message ); | |||
| } | |||
| condition.add( new IsSetCondition( ifCondition ) ); | |||
| } | |||
| // Add the 'unless' condition | |||
| if( null != unlessCondition ) | |||
| { | |||
| if( getLogger().isDebugEnabled() ) | |||
| // Split project->target dependencies | |||
| final int sep = dependency.indexOf( "->" ); | |||
| final String projectName; | |||
| final String targetName; | |||
| if( sep != -1 ) | |||
| { | |||
| final String message = REZ.getString( "ant.target-unless.notice", unlessCondition ); | |||
| getLogger().debug( message ); | |||
| 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 ); | |||
| } | |||
| condition.add( new NotCondition( new IsSetCondition( unlessCondition ) ) ); | |||
| dependsList.add( new Dependency( projectName, targetName ) ); | |||
| } | |||
| return condition; | |||
| return (Dependency[])dependsList.toArray( new Dependency[dependsList.size() ] ); | |||
| } | |||
| } | |||
| @@ -9,11 +9,10 @@ ati.attribue-unquoted.error=Expecting the value of attribute {0} to be enclosed | |||
| ant.project-banner.notice=Project {0} base directory: {1}. | |||
| ant.target-parse.notice=Parsing target: {0}. | |||
| ant.target-if.notice=Target if condition: {0} | |||
| ant.target-unless.notice=Target unless condition: {0} | |||
| ant.target-dependency.notice=Target dependency: {0} | |||
| ant.project-unexpected.error=Unexpected error building project. | |||
| ant.project-parse.error=Error parsing 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. | |||
| @@ -26,9 +25,10 @@ ant.import-malformed.error=Malformed import at {0}. If name or type attribute is | |||
| 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=Malformed version string "{0}" specified in version attribute of project. | |||
| ant.version-missing.error=Missing version attribute from project. | |||
| ant.bad-version.error=Incompatible build file version detected. Expected {0} but found {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. | |||
| 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}. | |||
| @@ -0,0 +1,3 @@ | |||
| #AbstractPropertyResolver | |||
| prop.mismatched-braces.error=Malformed property with mismatched }'s. | |||
| prop.missing-value.error=Unable to find "{0}" to expand during property resolution. | |||
| @@ -15,9 +15,9 @@ import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.avalon.excalibur.io.FileUtil; | |||
| import org.apache.avalon.framework.context.Context; | |||
| import org.apache.avalon.framework.context.ContextException; | |||
| import org.apache.avalon.framework.logger.Logger; | |||
| import org.apache.avalon.framework.service.ServiceException; | |||
| import org.apache.avalon.framework.service.ServiceManager; | |||
| import org.apache.avalon.framework.logger.Logger; | |||
| import org.apache.myrmidon.api.TaskContext; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.interfaces.model.DefaultNameValidator; | |||
| @@ -60,7 +60,6 @@ public class DefaultTaskContext | |||
| m_parent = parent; | |||
| m_serviceManager = serviceManager; | |||
| m_logger = logger; | |||
| //m_propertyResolver = (PropertyResolver)getService( PropertyResolver.class ); | |||
| } | |||
| /** | |||
| @@ -26,12 +26,12 @@ 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.framework.conditions.Condition; | |||
| import org.apache.myrmidon.interfaces.deployer.Deployer; | |||
| import org.apache.myrmidon.interfaces.deployer.DeploymentException; | |||
| import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||
| import org.apache.myrmidon.interfaces.executor.ExecutionFrame; | |||
| import org.apache.myrmidon.interfaces.executor.Executor; | |||
| import org.apache.myrmidon.interfaces.model.Dependency; | |||
| import org.apache.myrmidon.interfaces.model.Project; | |||
| import org.apache.myrmidon.interfaces.model.Target; | |||
| import org.apache.myrmidon.interfaces.model.TypeLib; | |||
| @@ -123,9 +123,7 @@ public class DefaultWorkspace | |||
| m_listenerSupport.projectStarted( project.getProjectName() ); | |||
| executeTarget( project, "<init>", project.getImplicitTarget(), entry.getFrame() ); | |||
| execute( project, target, entry ); | |||
| executeTarget( entry, target ); | |||
| m_listenerSupport.projectFinished( project.getProjectName() ); | |||
| } | |||
| @@ -307,105 +305,130 @@ public class DefaultWorkspace | |||
| /** | |||
| * Helper method to execute a target. | |||
| * | |||
| * @param project the Project | |||
| * @param targetName the name of the target | |||
| * @param entry the context | |||
| * @param entry the project to execute | |||
| * @param targetName the name of the target to execute | |||
| * @exception TaskException if an error occurs | |||
| */ | |||
| private void execute( final Project project, | |||
| final String targetName, | |||
| final ProjectEntry entry ) | |||
| private void executeTarget( final ProjectEntry entry, | |||
| final String targetName ) | |||
| throws TaskException | |||
| { | |||
| final int index = targetName.indexOf( "->" ); | |||
| if( -1 != index ) | |||
| // Locate the target | |||
| final Target target = entry.getProject().getTarget( targetName ); | |||
| if( null == target ) | |||
| { | |||
| final String name = targetName.substring( 0, index ); | |||
| final String otherTargetName = targetName.substring( index + 2 ); | |||
| final String message = REZ.getString( "no-target.error", targetName ); | |||
| throw new TaskException( message ); | |||
| } | |||
| final Project otherProject = getProject( name, project ); | |||
| final ProjectEntry otherEntry = getProjectEntry( otherProject ); | |||
| executeTarget( entry, targetName, target ); | |||
| } | |||
| //Execute target in referenced project | |||
| execute( otherProject, otherTargetName, otherEntry ); | |||
| /** | |||
| * 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; | |||
| } | |||
| final Target target = project.getTarget( targetName ); | |||
| if( null == target ) | |||
| if( state == TargetState.TRAVERSING ) | |||
| { | |||
| final String message = REZ.getString( "no-target.error", targetName ); | |||
| // Cycle in target dependencies | |||
| final String message = REZ.getString( "target-dependency-cycle.error", name ); | |||
| throw new TaskException( message ); | |||
| } | |||
| //add target to list of targets executed | |||
| entry.completeTarget( targetName ); | |||
| // 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() ); | |||
| } | |||
| //execute all dependencies | |||
| final String[] dependencies = target.getDependencies(); | |||
| // Named dependencies | |||
| final Dependency[] dependencies = target.getDependencies(); | |||
| for( int i = 0; i < dependencies.length; i++ ) | |||
| { | |||
| if( !entry.isTargetCompleted( dependencies[ 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 | |||
| { | |||
| execute( project, dependencies[ i ], entry ); | |||
| // Dependency in this project | |||
| executeTarget( entry, dependency.getTargetName() ); | |||
| } | |||
| } | |||
| executeTarget( project, targetName, target, entry.getFrame() ); | |||
| // Now execute the target itself | |||
| executeTargetNoDeps( entry, name, target ); | |||
| // Mark target as complete | |||
| entry.setTargetState( target, TargetState.FINISHED ); | |||
| } | |||
| /** | |||
| * Method to execute a particular target instance. | |||
| * Executes a target. Does not check whether the target has been | |||
| * executed already, and does not check that its dependencies have been | |||
| * executed. | |||
| * | |||
| * @param name the name of target | |||
| * @param target the target | |||
| * @param frame the frame in which to execute | |||
| * @exception TaskException if an error occurs | |||
| * @param entry the project to execute the target in. | |||
| * @param name the name of the target. | |||
| * @param target the target itself | |||
| */ | |||
| private void executeTarget( final Project project, | |||
| final String name, | |||
| final Target target, | |||
| final ExecutionFrame frame ) | |||
| private void executeTargetNoDeps( final ProjectEntry entry, | |||
| final String name, | |||
| final Target target ) | |||
| throws TaskException | |||
| { | |||
| //notify listeners | |||
| final Project project = entry.getProject(); | |||
| // Notify listeners | |||
| m_listenerSupport.targetStarted( project.getProjectName(), name ); | |||
| //check the condition associated with target. | |||
| //if it is not satisfied then skip target | |||
| final Condition condition = target.getCondition(); | |||
| if( null != condition ) | |||
| if( getLogger().isDebugEnabled() ) | |||
| { | |||
| try | |||
| { | |||
| final boolean result = condition.evaluate( frame.getContext() ); | |||
| if( !result ) | |||
| { | |||
| final String message = REZ.getString( "skip-target.notice", name ); | |||
| getLogger().debug( message ); | |||
| return; | |||
| } | |||
| } | |||
| catch( final TaskException te ) | |||
| { | |||
| final String message = REZ.getString( "condition-eval.error", name ); | |||
| throw new TaskException( message, te ); | |||
| } | |||
| final String message = REZ.getString( "exec-target.notice", project.getProjectName(), name ); | |||
| getLogger().debug( message ); | |||
| } | |||
| final String message = REZ.getString( "exec-target.notice", name ); | |||
| getLogger().debug( message ); | |||
| //frame.getContext().setProperty( Project.TARGET, target ); | |||
| //execute all tasks assciated with target | |||
| // Execute all tasks assciated with target | |||
| final Configuration[] tasks = target.getTasks(); | |||
| for( int i = 0; i < tasks.length; i++ ) | |||
| { | |||
| executeTask( tasks[ i ], frame ); | |||
| executeTask( tasks[ i ], entry.getFrame() ); | |||
| } | |||
| //notify listeners | |||
| // Notify listeners | |||
| m_listenerSupport.targetFinished(); | |||
| } | |||
| @@ -421,8 +444,11 @@ public class DefaultWorkspace | |||
| { | |||
| final String name = task.getName(); | |||
| final String message = REZ.getString( "exec-task.notice", name ); | |||
| getLogger().debug( message ); | |||
| if( getLogger().isDebugEnabled() ) | |||
| { | |||
| final String message = REZ.getString( "exec-task.notice", name ); | |||
| getLogger().debug( message ); | |||
| } | |||
| //is setting name even necessary ??? | |||
| frame.getContext().setProperty( TaskContext.NAME, name ); | |||
| @@ -7,12 +7,15 @@ | |||
| */ | |||
| package org.apache.myrmidon.components.workspace; | |||
| import java.util.ArrayList; | |||
| 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 detaisl for each project that is managed by ProjectManager. | |||
| * 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$ | |||
| @@ -21,7 +24,9 @@ final class ProjectEntry | |||
| { | |||
| private final Project m_project; | |||
| private final ExecutionFrame m_frame; | |||
| private final ArrayList m_targetsCompleted = new ArrayList(); | |||
| /** Map from Target -> TargetState for that target. */ | |||
| private final Map m_targetState = new HashMap(); | |||
| public ProjectEntry( final Project project, | |||
| final ExecutionFrame frame ) | |||
| @@ -40,13 +45,18 @@ final class ProjectEntry | |||
| return m_frame; | |||
| } | |||
| public boolean isTargetCompleted( final String target ) | |||
| public TargetState getTargetState( final Target target ) | |||
| { | |||
| return m_targetsCompleted.contains( target ); | |||
| TargetState state = (TargetState)m_targetState.get( target ); | |||
| if( state == null ) | |||
| { | |||
| state = TargetState.NOT_STARTED; | |||
| } | |||
| return state; | |||
| } | |||
| public void completeTarget( final String target ) | |||
| public void setTargetState( final Target target, final TargetState state ) | |||
| { | |||
| m_targetsCompleted.add( target ); | |||
| m_targetState.put( target, state ); | |||
| } | |||
| } | |||
| @@ -5,10 +5,9 @@ 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. | |||
| skip-target.notice=Skipping target {0} as it does not satisfy condition. | |||
| condition-eval.error=Error evaluating Condition for target {0}. | |||
| exec-target.notice=Executing target {0}. | |||
| 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}. | |||
| @@ -18,7 +17,3 @@ 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}. | |||
| #AbstractPropertyResolver | |||
| prop.mismatched-braces.error=Malformed property with mismatched }'s. | |||
| prop.missing-value.error=Unable to find "{0}" to expand during property resolution. | |||
| @@ -0,0 +1,34 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache 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 final static TargetState NOT_STARTED = new TargetState(); | |||
| /** | |||
| * Target has been started, and the dependencies of the target are being | |||
| * traversed. | |||
| */ | |||
| public final static TargetState TRAVERSING = new TargetState(); | |||
| /** Target has been completed. */ | |||
| public final static TargetState FINISHED = new TargetState(); | |||
| } | |||
| @@ -23,7 +23,7 @@ public interface ProjectBuilder | |||
| /** | |||
| * build a project from source. | |||
| * | |||
| * @param source the source | |||
| * @param source the project file path. | |||
| * @return the constructed Project | |||
| * @exception ProjectException if an error occurs | |||
| */ | |||
| @@ -0,0 +1,36 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache 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; | |||
| public Dependency( final String projectName, final String targetName ) | |||
| { | |||
| m_projectName = projectName; | |||
| m_targetName = targetName; | |||
| } | |||
| public String getProjectName() | |||
| { | |||
| return m_projectName; | |||
| } | |||
| public String getTargetName() | |||
| { | |||
| return m_targetName; | |||
| } | |||
| } | |||
| @@ -9,7 +9,6 @@ package org.apache.myrmidon.interfaces.model; | |||
| import java.util.ArrayList; | |||
| import org.apache.avalon.framework.configuration.Configuration; | |||
| import org.apache.myrmidon.framework.conditions.Condition; | |||
| /** | |||
| * Targets in build file. | |||
| @@ -21,19 +20,13 @@ public class Target | |||
| { | |||
| private final ArrayList m_dependencies = new ArrayList(); | |||
| private final ArrayList m_tasks = new ArrayList(); | |||
| private final Condition m_condition; | |||
| /** | |||
| * Constructor taking condition for target. | |||
| * | |||
| * @param condition the condition | |||
| * Constructs a target. | |||
| */ | |||
| public Target( final Condition condition, | |||
| final Configuration[] tasks, | |||
| final String[] dependencies ) | |||
| public Target( final Configuration[] tasks, | |||
| final Dependency[] dependencies ) | |||
| { | |||
| m_condition = condition; | |||
| for( int i = 0; i < tasks.length; i++ ) | |||
| { | |||
| m_tasks.add( tasks[ i ] ); | |||
| @@ -48,24 +41,14 @@ public class Target | |||
| } | |||
| } | |||
| /** | |||
| * Get condition under which target is executed. | |||
| * | |||
| * @return the condition for target or null | |||
| */ | |||
| public final Condition getCondition() | |||
| { | |||
| return m_condition; | |||
| } | |||
| /** | |||
| * Get dependencies of target | |||
| * | |||
| * @return the dependency list | |||
| */ | |||
| public final String[] getDependencies() | |||
| public final Dependency[] getDependencies() | |||
| { | |||
| return (String[])m_dependencies.toArray( new String[ 0 ] ); | |||
| return (Dependency[])m_dependencies.toArray( new Dependency[ 0 ] ); | |||
| } | |||
| /** | |||
| @@ -89,6 +89,14 @@ public abstract class AbstractFileSystemTest | |||
| m_charContent = "This is a test file." + eol + "With 2 lines in it." + eol; | |||
| } | |||
| /** | |||
| * Cleans-up test. | |||
| */ | |||
| protected void tearDown() throws Exception | |||
| { | |||
| m_manager.close(); | |||
| } | |||
| /** | |||
| * Tests resolution of absolute URI. | |||
| */ | |||
| @@ -11,13 +11,8 @@ import java.io.File; | |||
| import java.io.IOException; | |||
| import junit.framework.TestCase; | |||
| import org.apache.avalon.framework.ExceptionUtil; | |||
| import org.apache.avalon.framework.logger.LogKitLogger; | |||
| import org.apache.avalon.framework.logger.Logger; | |||
| import org.apache.log.Hierarchy; | |||
| import org.apache.log.LogTarget; | |||
| import org.apache.log.Priority; | |||
| import org.apache.log.format.PatternFormatter; | |||
| import org.apache.log.output.io.StreamTarget; | |||
| import org.apache.myrmidon.frontends.BasicLogger; | |||
| /** | |||
| * A base class for Myrmidon tests. Provides utility methods for locating | |||
| @@ -30,8 +25,7 @@ public abstract class AbstractMyrmidonTest | |||
| { | |||
| private final File m_testBaseDir; | |||
| private final File m_baseDir; | |||
| private final static String PATTERN = "[%8.8{category}] %{message}\\n%{throwable}"; | |||
| private Logger m_logger; | |||
| public AbstractMyrmidonTest( String name ) | |||
| { | |||
| @@ -49,10 +43,39 @@ public abstract class AbstractMyrmidonTest | |||
| * Locates a test resource, and asserts that the resource exists | |||
| */ | |||
| protected File getTestResource( final String name ) | |||
| { | |||
| return getTestResource( name, true ); | |||
| } | |||
| /** | |||
| * Locates a test resource. | |||
| */ | |||
| protected File getTestResource( final String name, final boolean mustExist ) | |||
| { | |||
| File file = new File( m_testBaseDir, name ); | |||
| file = getCanonicalFile( file ); | |||
| assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() ); | |||
| if( mustExist ) | |||
| { | |||
| assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() ); | |||
| } | |||
| else | |||
| { | |||
| assertTrue( "Test file \"" + file + "\" should not exist.", !file.exists() ); | |||
| } | |||
| return file; | |||
| } | |||
| /** | |||
| * Locates a test directory, creating it if it does not exist. | |||
| */ | |||
| protected File getTestDirectory( final String name ) | |||
| { | |||
| File file = new File( m_testBaseDir, name ); | |||
| file = getCanonicalFile( file ); | |||
| assertTrue( "Test directory \"" + file + "\" does not exist or is not a directory.", | |||
| file.isDirectory() || file.mkdirs() ); | |||
| return file; | |||
| } | |||
| @@ -83,18 +106,13 @@ public abstract class AbstractMyrmidonTest | |||
| /** | |||
| * Creates a logger. | |||
| */ | |||
| protected Logger createLogger() | |||
| protected Logger getLogger() | |||
| { | |||
| // Setup a logger | |||
| final Priority priority = Priority.WARN; | |||
| final org.apache.log.Logger targetLogger = Hierarchy.getDefaultHierarchy().getLoggerFor( "myrmidon" ); | |||
| final PatternFormatter formatter = new PatternFormatter( PATTERN ); | |||
| final StreamTarget target = new StreamTarget( System.out, formatter ); | |||
| targetLogger.setLogTargets( new LogTarget[]{target} ); | |||
| targetLogger.setPriority( priority ); | |||
| return new LogKitLogger( targetLogger ); | |||
| if( m_logger == null ) | |||
| { | |||
| m_logger = new BasicLogger( "[test]", BasicLogger.LEVEL_WARN ); | |||
| } | |||
| return m_logger; | |||
| } | |||
| /** | |||
| @@ -105,6 +123,12 @@ public abstract class AbstractMyrmidonTest | |||
| */ | |||
| protected void assertSameMessage( final String[] messages, final Throwable throwable ) | |||
| { | |||
| //System.out.println( "exception:" ); | |||
| //for( Throwable t = throwable; t != null; t = ExceptionUtil.getCause( t, true ) ) | |||
| //{ | |||
| // System.out.println( " " + t.getMessage() ); | |||
| //} | |||
| Throwable current = throwable; | |||
| for( int i = 0; i < messages.length; i++ ) | |||
| { | |||
| @@ -125,7 +149,7 @@ public abstract class AbstractMyrmidonTest | |||
| */ | |||
| protected void assertSameMessage( final String message, final Throwable throwable ) | |||
| { | |||
| assertEquals( message, throwable.getMessage() ); | |||
| assertSameMessage( new String[] { message }, throwable ); | |||
| } | |||
| /** | |||
| @@ -54,7 +54,7 @@ public class AbstractProjectTest | |||
| // Need to set the context classloader - The default embeddor uses it | |||
| Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); | |||
| final Logger logger = createLogger(); | |||
| final Logger logger = getLogger(); | |||
| m_embeddor = new DefaultEmbeddor(); | |||
| m_embeddor.enableLogging( logger ); | |||
| @@ -14,7 +14,6 @@ import org.apache.aut.converter.Converter; | |||
| import org.apache.avalon.framework.logger.LogEnabled; | |||
| 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.avalon.framework.service.Serviceable; | |||
| import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| @@ -24,20 +23,19 @@ import org.apache.myrmidon.components.converter.DefaultConverterRegistry; | |||
| import org.apache.myrmidon.components.converter.DefaultMasterConverter; | |||
| import org.apache.myrmidon.components.deployer.DefaultDeployer; | |||
| import org.apache.myrmidon.components.extensions.DefaultExtensionManager; | |||
| import org.apache.myrmidon.components.property.DefaultPropertyResolver; | |||
| import org.apache.myrmidon.components.role.DefaultRoleManager; | |||
| import org.apache.myrmidon.components.type.DefaultTypeManager; | |||
| import org.apache.myrmidon.components.property.DefaultPropertyResolver; | |||
| 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.extensions.ExtensionManager; | |||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
| import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
| import org.apache.myrmidon.interfaces.role.RoleManager; | |||
| import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
| import org.apache.myrmidon.interfaces.type.TypeException; | |||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
| /** | |||
| * A base class for tests for the default components. | |||
| @@ -48,7 +46,6 @@ public abstract class AbstractComponentTest | |||
| extends AbstractMyrmidonTest | |||
| { | |||
| private DefaultServiceManager m_serviceManager; | |||
| private Logger m_logger; | |||
| public AbstractComponentTest( final String name ) | |||
| { | |||
| @@ -58,95 +55,85 @@ public abstract class AbstractComponentTest | |||
| /** | |||
| * Returns the component manager containing the components to test. | |||
| */ | |||
| protected final ServiceManager getServiceManager() | |||
| { | |||
| return m_serviceManager; | |||
| } | |||
| protected final Logger getLogger() | |||
| protected final ServiceManager getServiceManager() throws Exception | |||
| { | |||
| return m_logger; | |||
| } | |||
| /** | |||
| * Returns the type manager. | |||
| */ | |||
| protected TypeManager getTypeManager() | |||
| throws ServiceException | |||
| { | |||
| return (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); | |||
| } | |||
| /** | |||
| * Setup the test case - prepares the set of components. | |||
| */ | |||
| protected void setUp() | |||
| throws Exception | |||
| { | |||
| m_logger = createLogger(); | |||
| if( m_serviceManager == null ) | |||
| { | |||
| Logger logger = getLogger(); | |||
| // Create the components | |||
| m_serviceManager = new DefaultServiceManager(); | |||
| List components = new ArrayList(); | |||
| // Create the components | |||
| m_serviceManager = new DefaultServiceManager(); | |||
| List components = new ArrayList(); | |||
| Object component = new DefaultMasterConverter(); | |||
| m_serviceManager.put( Converter.ROLE, component ); | |||
| components.add( component ); | |||
| Object component = new DefaultMasterConverter(); | |||
| m_serviceManager.put( Converter.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultConverterRegistry(); | |||
| m_serviceManager.put( ConverterRegistry.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultConverterRegistry(); | |||
| m_serviceManager.put( ConverterRegistry.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultTypeManager(); | |||
| m_serviceManager.put( TypeManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultTypeManager(); | |||
| m_serviceManager.put( TypeManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultConfigurer(); | |||
| m_serviceManager.put( Configurer.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultConfigurer(); | |||
| m_serviceManager.put( Configurer.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultDeployer(); | |||
| m_serviceManager.put( Deployer.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultDeployer(); | |||
| m_serviceManager.put( Deployer.ROLE, component ); | |||
| components.add( component ); | |||
| final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager(); | |||
| classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() ); | |||
| m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr ); | |||
| components.add( classLoaderMgr ); | |||
| final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager(); | |||
| classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() ); | |||
| m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr ); | |||
| components.add( classLoaderMgr ); | |||
| component = new DefaultExtensionManager(); | |||
| m_serviceManager.put( ExtensionManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultExtensionManager(); | |||
| m_serviceManager.put( ExtensionManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultRoleManager(); | |||
| m_serviceManager.put( RoleManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultRoleManager(); | |||
| m_serviceManager.put( RoleManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultPropertyResolver(); | |||
| m_serviceManager.put( PropertyResolver.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultPropertyResolver(); | |||
| m_serviceManager.put( PropertyResolver.ROLE, component ); | |||
| components.add( component ); | |||
| // Log enable the components | |||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
| { | |||
| Object obj = iterator.next(); | |||
| if( obj instanceof LogEnabled ) | |||
| // Log enable the components | |||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
| { | |||
| final LogEnabled logEnabled = (LogEnabled)obj; | |||
| logEnabled.enableLogging( m_logger ); | |||
| Object obj = iterator.next(); | |||
| if( obj instanceof LogEnabled ) | |||
| { | |||
| final LogEnabled logEnabled = (LogEnabled)obj; | |||
| logEnabled.enableLogging( logger ); | |||
| } | |||
| } | |||
| } | |||
| // Compose the components | |||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
| { | |||
| Object obj = iterator.next(); | |||
| if( obj instanceof Serviceable ) | |||
| // Compose the components | |||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
| { | |||
| final Serviceable serviceable = (Serviceable)obj; | |||
| serviceable.service( m_serviceManager ); | |||
| Object obj = iterator.next(); | |||
| if( obj instanceof Serviceable ) | |||
| { | |||
| final Serviceable serviceable = (Serviceable)obj; | |||
| serviceable.service( m_serviceManager ); | |||
| } | |||
| } | |||
| } | |||
| return m_serviceManager; | |||
| } | |||
| /** | |||
| * Returns the type manager. | |||
| */ | |||
| protected TypeManager getTypeManager() | |||
| throws Exception | |||
| { | |||
| return (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); | |||
| } | |||
| /** | |||
| @@ -179,7 +166,7 @@ public abstract class AbstractComponentTest | |||
| protected void registerConverter( final Class converterClass, | |||
| final Class sourceClass, | |||
| final Class destClass ) | |||
| throws ServiceException, TypeException | |||
| throws Exception | |||
| { | |||
| ConverterRegistry converterRegistry = (ConverterRegistry)getServiceManager().lookup( ConverterRegistry.ROLE ); | |||
| converterRegistry.registerConverter( converterClass.getName(), sourceClass.getName(), destClass.getName() ); | |||
| @@ -8,9 +8,13 @@ | |||
| package org.apache.myrmidon.components.builder; | |||
| import java.io.File; | |||
| import java.util.Arrays; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.avalon.excalibur.io.FileUtil; | |||
| import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| import org.apache.myrmidon.interfaces.builder.ProjectException; | |||
| import org.apache.myrmidon.interfaces.model.Project; | |||
| /** | |||
| * Test cases for {@link DefaultProjectBuilder}. | |||
| @@ -22,7 +26,7 @@ public class DefaultProjectBuilderTest | |||
| extends AbstractMyrmidonTest | |||
| { | |||
| private final static Resources REZ | |||
| = ResourceManager.getPackageResources( DefaultProjectBuilder.class ); | |||
| = ResourceManager.getPackageResources( DefaultProjectBuilderTest.class ); | |||
| private DefaultProjectBuilder m_builder; | |||
| @@ -35,11 +39,227 @@ public class DefaultProjectBuilderTest | |||
| { | |||
| super.setUp(); | |||
| m_builder = new DefaultProjectBuilder(); | |||
| m_builder.enableLogging( createLogger() ); | |||
| m_builder.enableLogging( getLogger() ); | |||
| } | |||
| /** | |||
| * Test validation of project and target names. | |||
| * Creates a project, with default values set. | |||
| */ | |||
| private DefaultProject createProject( final File projFile ) | |||
| { | |||
| final DefaultProject project = new DefaultProject(); | |||
| project.setProjectName( FileUtil.removeExtension( projFile.getName() ) ); | |||
| project.setBaseDirectory( getTestDirectory( "." ) ); | |||
| project.setDefaultTargetName( "main" ); | |||
| return project; | |||
| } | |||
| /** | |||
| * Tests bad project file name. | |||
| */ | |||
| public void testProjectFileName() throws Exception | |||
| { | |||
| // Test with a file that does not exist | |||
| File projFile = getTestResource( "unknown.ant", false ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.no-project-file.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| // Test with a directory | |||
| projFile = getTestDirectory( "some-dir" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.no-project-file.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| } | |||
| /** | |||
| * Tests error reporting when the project file contains badly formed XML. | |||
| */ | |||
| public void testBadlyFormedFile() throws Exception | |||
| { | |||
| final File projFile = getTestResource( "bad-xml.ant" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.project-parse.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| } | |||
| /** | |||
| * Tests building a project with default values for project name, base dir | |||
| * and default target. | |||
| */ | |||
| public void testDefaults() throws Exception | |||
| { | |||
| // Build project | |||
| final File projFile = getTestResource( "defaults.ant" ); | |||
| Project project = m_builder.build( projFile.getAbsolutePath() ); | |||
| // Compare against expected project | |||
| DefaultProject expected = createProject( projFile ); | |||
| assertSameProject( expected, project ); | |||
| } | |||
| /** | |||
| * Tests setting the project name. | |||
| */ | |||
| public void testProjectName() throws Exception | |||
| { | |||
| // Build project | |||
| final File projFile = getTestResource( "set-project-name.ant" ); | |||
| Project project = m_builder.build( projFile.getAbsolutePath() ); | |||
| // Compare against expected project | |||
| DefaultProject expected = createProject( projFile ); | |||
| expected.setProjectName( "some-project" ); | |||
| assertSameProject( expected, project ); | |||
| } | |||
| /** | |||
| * Tests setting the base directory. | |||
| */ | |||
| public void testBaseDirectory() throws Exception | |||
| { | |||
| // Build project | |||
| final File projFile = getTestResource( "set-base-dir.ant" ); | |||
| Project project = m_builder.build( projFile.getAbsolutePath() ); | |||
| // Compare against expected project | |||
| DefaultProject expected = createProject( projFile ); | |||
| final File baseDir = getTestDirectory( "other-base-dir" ); | |||
| expected.setBaseDirectory( baseDir ); | |||
| assertSameProject( expected, project ); | |||
| } | |||
| /** | |||
| * Tests setting the default target name. | |||
| */ | |||
| public void testDefaultTarget() throws Exception | |||
| { | |||
| // Build project | |||
| final File projFile = getTestResource( "set-default-target.ant" ); | |||
| Project project = m_builder.build( projFile.getAbsolutePath() ); | |||
| // Compare against expected project | |||
| DefaultProject expected = createProject( projFile ); | |||
| expected.setDefaultTargetName( "some-target" ); | |||
| assertSameProject( expected, project ); | |||
| } | |||
| /** | |||
| * Tests missing, invalid and incompatible project version. | |||
| */ | |||
| public void testProjectVersion() throws Exception | |||
| { | |||
| // No version | |||
| File projFile = getTestResource( "no-version.ant" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.version-missing.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| // Badly formed version | |||
| projFile = getTestResource( "bad-version.ant" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.malformed.version", "ant2" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| // Incompatible version | |||
| projFile = getTestResource( "mismatched-version.ant" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.bad-version.error", "2.0.0", "1.0.2" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| } | |||
| /** | |||
| * Asserts that 2 projects are identical. | |||
| */ | |||
| protected void assertSameProject( final Project expected, | |||
| final Project project ) | |||
| { | |||
| assertEquals( expected.getProjectName(), project.getProjectName() ); | |||
| assertEquals( expected.getBaseDirectory(), project.getBaseDirectory() ); | |||
| assertEquals( expected.getDefaultTargetName(), project.getDefaultTargetName() ); | |||
| // TODO - make sure each of the projects are the same | |||
| assertTrue( Arrays.equals( expected.getProjectNames(), project.getProjectNames() ) ); | |||
| // TODO - make sure the implicit targets are the same | |||
| // TODO - make sure each of the targets are the same | |||
| assertTrue( Arrays.equals( expected.getTargetNames(), project.getTargetNames() ) ); | |||
| // TODO - implement TypeLib.equals(), or use a comparator | |||
| assertTrue( Arrays.equals( expected.getTypeLibs(), project.getTypeLibs() ) ); | |||
| } | |||
| /** | |||
| * Tests validation of project and target names. | |||
| */ | |||
| public void testNameValidation() throws Exception | |||
| { | |||
| @@ -52,7 +272,12 @@ public class DefaultProjectBuilderTest | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| assertSameMessage( REZ.getString( "ant.project-bad-name.error" ), e ); | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", badProjectFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.project-bad-name.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| // Check bad target name | |||
| @@ -64,7 +289,13 @@ public class DefaultProjectBuilderTest | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // TODO - check error message | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", badTargetFile.getAbsolutePath() ), | |||
| // TODO - check error message | |||
| null | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| } | |||
| } | |||
| @@ -5,53 +5,51 @@ | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.myrmidon.components.workspace; | |||
| package org.apache.myrmidon.components.property; | |||
| import java.io.File; | |||
| import java.util.Date; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.avalon.framework.context.Context; | |||
| import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.components.AbstractComponentTest; | |||
| import org.apache.myrmidon.components.property.DefaultPropertyResolver; | |||
| import org.apache.myrmidon.components.workspace.DefaultTaskContext; | |||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
| /** | |||
| * Functional tests for {@link DefaultPropertyResolver}. | |||
| * General-purpose property resolver test cases. | |||
| * | |||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class DefaultPropertyResolverTest | |||
| extends AbstractComponentTest | |||
| public abstract class AbstractPropertyResolverTest | |||
| extends AbstractMyrmidonTest | |||
| { | |||
| protected final static Resources REZ | |||
| = ResourceManager.getPackageResources( DefaultPropertyResolver.class ); | |||
| = ResourceManager.getPackageResources( AbstractPropertyResolverTest.class ); | |||
| protected PropertyResolver m_resolver; | |||
| protected DefaultTaskContext m_context; | |||
| public DefaultPropertyResolverTest( String name ) | |||
| public AbstractPropertyResolverTest( String name ) | |||
| { | |||
| super( name ); | |||
| } | |||
| protected void setUp() throws Exception | |||
| { | |||
| super.setUp(); | |||
| m_resolver = createResolver(); | |||
| m_context = new DefaultTaskContext( null, getServiceManager(), getLogger() ); | |||
| m_context = new DefaultTaskContext( null, null, getLogger() ); | |||
| m_context.setProperty( "intProp", new Integer( 333 ) ); | |||
| m_context.setProperty( "stringProp", "String property" ); | |||
| } | |||
| protected PropertyResolver createResolver() | |||
| { | |||
| return new DefaultPropertyResolver(); | |||
| } | |||
| /** | |||
| * Creates the resolver to test. | |||
| */ | |||
| protected abstract PropertyResolver createResolver(); | |||
| /** | |||
| * Test property resolution with various different typed properties. | |||
| @@ -73,7 +71,7 @@ public class DefaultPropertyResolverTest | |||
| throws Exception | |||
| { | |||
| m_context.setProperty( "typedProp", propObject ); | |||
| String propString = propObject.toString(); | |||
| final String propString = propObject.toString(); | |||
| doTestResolution( "${typedProp}", propObject, m_context ); | |||
| doTestResolution( "${typedProp} with following text", | |||
| @@ -96,23 +94,6 @@ public class DefaultPropertyResolverTest | |||
| doTestResolution( "before ${prop2} between ${prop1} after", | |||
| "before value2 between value1 after", m_context ); | |||
| doTestResolution( "${prop1}-${int1}-${prop2}", "value1-123-value2", m_context ); | |||
| } | |||
| /** | |||
| * Tests handing undefined property. | |||
| */ | |||
| public void testUndefinedProp() throws Exception | |||
| { | |||
| String undefinedProp = "undefinedProperty"; | |||
| doTestFailure( "${" + undefinedProp + "}", | |||
| REZ.getString( "prop.missing-value.error", undefinedProp ), | |||
| m_context ); | |||
| //TODO - "" should be disallowed as a property name | |||
| doTestFailure( "${}", | |||
| REZ.getString( "prop.missing-value.error", "" ), | |||
| m_context ); | |||
| } | |||
| /** | |||
| @@ -131,18 +112,17 @@ public class DefaultPropertyResolverTest | |||
| /* TODO - need to handle these cases. */ | |||
| // testFailure( "${bad${}", "", m_context ); | |||
| // testFailure( "${ }", "", m_context ); | |||
| } | |||
| /** | |||
| * Resolves the property using the supplied context, and checks the result. | |||
| */ | |||
| protected void doTestResolution( String value, | |||
| Object expected, | |||
| Context context ) | |||
| protected void doTestResolution( final String value, | |||
| final Object expected, | |||
| final Context context ) | |||
| throws Exception | |||
| { | |||
| Object resolved = m_resolver.resolveProperties( value, context ); | |||
| final Object resolved = m_resolver.resolveProperties( value, context ); | |||
| assertEquals( expected, resolved ); | |||
| } | |||
| @@ -151,9 +131,9 @@ public class DefaultPropertyResolverTest | |||
| * Attempts to resolve the value using the supplied context, expecting to | |||
| * fail with the supplied error message. | |||
| */ | |||
| protected void doTestFailure( String value, | |||
| String expectedErrorMessage, | |||
| Context context ) | |||
| protected void doTestFailure( final String value, | |||
| final String expectedErrorMessage, | |||
| final Context context ) | |||
| { | |||
| try | |||
| { | |||
| @@ -5,19 +5,18 @@ | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.myrmidon.components.workspace; | |||
| package org.apache.myrmidon.components.property; | |||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
| import org.apache.myrmidon.components.property.ClassicPropertyResolver; | |||
| /** | |||
| * A test for {@link ClassicPropertyResolver} | |||
| * A test for {@link ClassicPropertyResolver}. | |||
| * | |||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class ClassicPropertyResolverTest | |||
| extends DefaultPropertyResolverTest | |||
| extends AbstractPropertyResolverTest | |||
| { | |||
| public ClassicPropertyResolverTest( String name ) | |||
| { | |||
| @@ -34,8 +33,7 @@ public class ClassicPropertyResolverTest | |||
| */ | |||
| public void testUndefinedProp() throws Exception | |||
| { | |||
| String undefinedProp = "undefinedProperty"; | |||
| final String undefinedProp = "undefinedProperty"; | |||
| final String propRef = "${" + undefinedProp + "}"; | |||
| doTestResolution( propRef, propRef, m_context ); | |||
| } | |||
| @@ -0,0 +1,46 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache 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; | |||
| /** | |||
| * Functional tests for {@link DefaultPropertyResolver}. | |||
| * | |||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class DefaultPropertyResolverTest | |||
| extends AbstractPropertyResolverTest | |||
| { | |||
| public DefaultPropertyResolverTest( String name ) | |||
| { | |||
| super( name ); | |||
| } | |||
| protected PropertyResolver createResolver() | |||
| { | |||
| return new DefaultPropertyResolver(); | |||
| } | |||
| /** | |||
| * Tests handing undefined property. | |||
| */ | |||
| public void testUndefinedProp() throws Exception | |||
| { | |||
| final String undefinedProp = "undefinedProperty"; | |||
| doTestFailure( "${" + undefinedProp + "}", | |||
| REZ.getString( "prop.missing-value.error", undefinedProp ), | |||
| m_context ); | |||
| //TODO - "" should be disallowed as a property name | |||
| doTestFailure( "${}", | |||
| REZ.getString( "prop.missing-value.error", "" ), | |||
| m_context ); | |||
| } | |||
| } | |||
| @@ -44,11 +44,9 @@ public class InstantiatingServiceManagerTest | |||
| protected void setUp() | |||
| throws Exception | |||
| { | |||
| super.setUp(); | |||
| // Set-up the service manager | |||
| m_serviceManager = new InstantiatingServiceManager(); | |||
| m_serviceManager.enableLogging( createLogger() ); | |||
| m_serviceManager.enableLogging( getLogger() ); | |||
| m_serviceManager.service( getServiceManager() ); | |||
| m_serviceManager.parameterize( m_parameters ); | |||
| } | |||
| @@ -89,6 +89,14 @@ public abstract class AbstractFileSystemTest | |||
| m_charContent = "This is a test file." + eol + "With 2 lines in it." + eol; | |||
| } | |||
| /** | |||
| * Cleans-up test. | |||
| */ | |||
| protected void tearDown() throws Exception | |||
| { | |||
| m_manager.close(); | |||
| } | |||
| /** | |||
| * Tests resolution of absolute URI. | |||
| */ | |||
| @@ -11,13 +11,8 @@ import java.io.File; | |||
| import java.io.IOException; | |||
| import junit.framework.TestCase; | |||
| import org.apache.avalon.framework.ExceptionUtil; | |||
| import org.apache.avalon.framework.logger.LogKitLogger; | |||
| import org.apache.avalon.framework.logger.Logger; | |||
| import org.apache.log.Hierarchy; | |||
| import org.apache.log.LogTarget; | |||
| import org.apache.log.Priority; | |||
| import org.apache.log.format.PatternFormatter; | |||
| import org.apache.log.output.io.StreamTarget; | |||
| import org.apache.myrmidon.frontends.BasicLogger; | |||
| /** | |||
| * A base class for Myrmidon tests. Provides utility methods for locating | |||
| @@ -30,8 +25,7 @@ public abstract class AbstractMyrmidonTest | |||
| { | |||
| private final File m_testBaseDir; | |||
| private final File m_baseDir; | |||
| private final static String PATTERN = "[%8.8{category}] %{message}\\n%{throwable}"; | |||
| private Logger m_logger; | |||
| public AbstractMyrmidonTest( String name ) | |||
| { | |||
| @@ -49,10 +43,39 @@ public abstract class AbstractMyrmidonTest | |||
| * Locates a test resource, and asserts that the resource exists | |||
| */ | |||
| protected File getTestResource( final String name ) | |||
| { | |||
| return getTestResource( name, true ); | |||
| } | |||
| /** | |||
| * Locates a test resource. | |||
| */ | |||
| protected File getTestResource( final String name, final boolean mustExist ) | |||
| { | |||
| File file = new File( m_testBaseDir, name ); | |||
| file = getCanonicalFile( file ); | |||
| assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() ); | |||
| if( mustExist ) | |||
| { | |||
| assertTrue( "Test file \"" + file + "\" does not exist.", file.exists() ); | |||
| } | |||
| else | |||
| { | |||
| assertTrue( "Test file \"" + file + "\" should not exist.", !file.exists() ); | |||
| } | |||
| return file; | |||
| } | |||
| /** | |||
| * Locates a test directory, creating it if it does not exist. | |||
| */ | |||
| protected File getTestDirectory( final String name ) | |||
| { | |||
| File file = new File( m_testBaseDir, name ); | |||
| file = getCanonicalFile( file ); | |||
| assertTrue( "Test directory \"" + file + "\" does not exist or is not a directory.", | |||
| file.isDirectory() || file.mkdirs() ); | |||
| return file; | |||
| } | |||
| @@ -83,18 +106,13 @@ public abstract class AbstractMyrmidonTest | |||
| /** | |||
| * Creates a logger. | |||
| */ | |||
| protected Logger createLogger() | |||
| protected Logger getLogger() | |||
| { | |||
| // Setup a logger | |||
| final Priority priority = Priority.WARN; | |||
| final org.apache.log.Logger targetLogger = Hierarchy.getDefaultHierarchy().getLoggerFor( "myrmidon" ); | |||
| final PatternFormatter formatter = new PatternFormatter( PATTERN ); | |||
| final StreamTarget target = new StreamTarget( System.out, formatter ); | |||
| targetLogger.setLogTargets( new LogTarget[]{target} ); | |||
| targetLogger.setPriority( priority ); | |||
| return new LogKitLogger( targetLogger ); | |||
| if( m_logger == null ) | |||
| { | |||
| m_logger = new BasicLogger( "[test]", BasicLogger.LEVEL_WARN ); | |||
| } | |||
| return m_logger; | |||
| } | |||
| /** | |||
| @@ -105,6 +123,12 @@ public abstract class AbstractMyrmidonTest | |||
| */ | |||
| protected void assertSameMessage( final String[] messages, final Throwable throwable ) | |||
| { | |||
| //System.out.println( "exception:" ); | |||
| //for( Throwable t = throwable; t != null; t = ExceptionUtil.getCause( t, true ) ) | |||
| //{ | |||
| // System.out.println( " " + t.getMessage() ); | |||
| //} | |||
| Throwable current = throwable; | |||
| for( int i = 0; i < messages.length; i++ ) | |||
| { | |||
| @@ -125,7 +149,7 @@ public abstract class AbstractMyrmidonTest | |||
| */ | |||
| protected void assertSameMessage( final String message, final Throwable throwable ) | |||
| { | |||
| assertEquals( message, throwable.getMessage() ); | |||
| assertSameMessage( new String[] { message }, throwable ); | |||
| } | |||
| /** | |||
| @@ -54,7 +54,7 @@ public class AbstractProjectTest | |||
| // Need to set the context classloader - The default embeddor uses it | |||
| Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); | |||
| final Logger logger = createLogger(); | |||
| final Logger logger = getLogger(); | |||
| m_embeddor = new DefaultEmbeddor(); | |||
| m_embeddor.enableLogging( logger ); | |||
| @@ -14,7 +14,6 @@ import org.apache.aut.converter.Converter; | |||
| import org.apache.avalon.framework.logger.LogEnabled; | |||
| 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.avalon.framework.service.Serviceable; | |||
| import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| @@ -24,20 +23,19 @@ import org.apache.myrmidon.components.converter.DefaultConverterRegistry; | |||
| import org.apache.myrmidon.components.converter.DefaultMasterConverter; | |||
| import org.apache.myrmidon.components.deployer.DefaultDeployer; | |||
| import org.apache.myrmidon.components.extensions.DefaultExtensionManager; | |||
| import org.apache.myrmidon.components.property.DefaultPropertyResolver; | |||
| import org.apache.myrmidon.components.role.DefaultRoleManager; | |||
| import org.apache.myrmidon.components.type.DefaultTypeManager; | |||
| import org.apache.myrmidon.components.property.DefaultPropertyResolver; | |||
| 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.extensions.ExtensionManager; | |||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
| import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
| import org.apache.myrmidon.interfaces.role.RoleManager; | |||
| import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
| import org.apache.myrmidon.interfaces.type.TypeException; | |||
| import org.apache.myrmidon.interfaces.type.TypeManager; | |||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
| /** | |||
| * A base class for tests for the default components. | |||
| @@ -48,7 +46,6 @@ public abstract class AbstractComponentTest | |||
| extends AbstractMyrmidonTest | |||
| { | |||
| private DefaultServiceManager m_serviceManager; | |||
| private Logger m_logger; | |||
| public AbstractComponentTest( final String name ) | |||
| { | |||
| @@ -58,95 +55,85 @@ public abstract class AbstractComponentTest | |||
| /** | |||
| * Returns the component manager containing the components to test. | |||
| */ | |||
| protected final ServiceManager getServiceManager() | |||
| { | |||
| return m_serviceManager; | |||
| } | |||
| protected final Logger getLogger() | |||
| protected final ServiceManager getServiceManager() throws Exception | |||
| { | |||
| return m_logger; | |||
| } | |||
| /** | |||
| * Returns the type manager. | |||
| */ | |||
| protected TypeManager getTypeManager() | |||
| throws ServiceException | |||
| { | |||
| return (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); | |||
| } | |||
| /** | |||
| * Setup the test case - prepares the set of components. | |||
| */ | |||
| protected void setUp() | |||
| throws Exception | |||
| { | |||
| m_logger = createLogger(); | |||
| if( m_serviceManager == null ) | |||
| { | |||
| Logger logger = getLogger(); | |||
| // Create the components | |||
| m_serviceManager = new DefaultServiceManager(); | |||
| List components = new ArrayList(); | |||
| // Create the components | |||
| m_serviceManager = new DefaultServiceManager(); | |||
| List components = new ArrayList(); | |||
| Object component = new DefaultMasterConverter(); | |||
| m_serviceManager.put( Converter.ROLE, component ); | |||
| components.add( component ); | |||
| Object component = new DefaultMasterConverter(); | |||
| m_serviceManager.put( Converter.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultConverterRegistry(); | |||
| m_serviceManager.put( ConverterRegistry.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultConverterRegistry(); | |||
| m_serviceManager.put( ConverterRegistry.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultTypeManager(); | |||
| m_serviceManager.put( TypeManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultTypeManager(); | |||
| m_serviceManager.put( TypeManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultConfigurer(); | |||
| m_serviceManager.put( Configurer.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultConfigurer(); | |||
| m_serviceManager.put( Configurer.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultDeployer(); | |||
| m_serviceManager.put( Deployer.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultDeployer(); | |||
| m_serviceManager.put( Deployer.ROLE, component ); | |||
| components.add( component ); | |||
| final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager(); | |||
| classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() ); | |||
| m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr ); | |||
| components.add( classLoaderMgr ); | |||
| final DefaultClassLoaderManager classLoaderMgr = new DefaultClassLoaderManager(); | |||
| classLoaderMgr.setBaseClassLoader( getClass().getClassLoader() ); | |||
| m_serviceManager.put( ClassLoaderManager.ROLE, classLoaderMgr ); | |||
| components.add( classLoaderMgr ); | |||
| component = new DefaultExtensionManager(); | |||
| m_serviceManager.put( ExtensionManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultExtensionManager(); | |||
| m_serviceManager.put( ExtensionManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultRoleManager(); | |||
| m_serviceManager.put( RoleManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultRoleManager(); | |||
| m_serviceManager.put( RoleManager.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultPropertyResolver(); | |||
| m_serviceManager.put( PropertyResolver.ROLE, component ); | |||
| components.add( component ); | |||
| component = new DefaultPropertyResolver(); | |||
| m_serviceManager.put( PropertyResolver.ROLE, component ); | |||
| components.add( component ); | |||
| // Log enable the components | |||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
| { | |||
| Object obj = iterator.next(); | |||
| if( obj instanceof LogEnabled ) | |||
| // Log enable the components | |||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
| { | |||
| final LogEnabled logEnabled = (LogEnabled)obj; | |||
| logEnabled.enableLogging( m_logger ); | |||
| Object obj = iterator.next(); | |||
| if( obj instanceof LogEnabled ) | |||
| { | |||
| final LogEnabled logEnabled = (LogEnabled)obj; | |||
| logEnabled.enableLogging( logger ); | |||
| } | |||
| } | |||
| } | |||
| // Compose the components | |||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
| { | |||
| Object obj = iterator.next(); | |||
| if( obj instanceof Serviceable ) | |||
| // Compose the components | |||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
| { | |||
| final Serviceable serviceable = (Serviceable)obj; | |||
| serviceable.service( m_serviceManager ); | |||
| Object obj = iterator.next(); | |||
| if( obj instanceof Serviceable ) | |||
| { | |||
| final Serviceable serviceable = (Serviceable)obj; | |||
| serviceable.service( m_serviceManager ); | |||
| } | |||
| } | |||
| } | |||
| return m_serviceManager; | |||
| } | |||
| /** | |||
| * Returns the type manager. | |||
| */ | |||
| protected TypeManager getTypeManager() | |||
| throws Exception | |||
| { | |||
| return (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); | |||
| } | |||
| /** | |||
| @@ -179,7 +166,7 @@ public abstract class AbstractComponentTest | |||
| protected void registerConverter( final Class converterClass, | |||
| final Class sourceClass, | |||
| final Class destClass ) | |||
| throws ServiceException, TypeException | |||
| throws Exception | |||
| { | |||
| ConverterRegistry converterRegistry = (ConverterRegistry)getServiceManager().lookup( ConverterRegistry.ROLE ); | |||
| converterRegistry.registerConverter( converterClass.getName(), sourceClass.getName(), destClass.getName() ); | |||
| @@ -8,9 +8,13 @@ | |||
| package org.apache.myrmidon.components.builder; | |||
| import java.io.File; | |||
| import java.util.Arrays; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.avalon.excalibur.io.FileUtil; | |||
| import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| import org.apache.myrmidon.interfaces.builder.ProjectException; | |||
| import org.apache.myrmidon.interfaces.model.Project; | |||
| /** | |||
| * Test cases for {@link DefaultProjectBuilder}. | |||
| @@ -22,7 +26,7 @@ public class DefaultProjectBuilderTest | |||
| extends AbstractMyrmidonTest | |||
| { | |||
| private final static Resources REZ | |||
| = ResourceManager.getPackageResources( DefaultProjectBuilder.class ); | |||
| = ResourceManager.getPackageResources( DefaultProjectBuilderTest.class ); | |||
| private DefaultProjectBuilder m_builder; | |||
| @@ -35,11 +39,227 @@ public class DefaultProjectBuilderTest | |||
| { | |||
| super.setUp(); | |||
| m_builder = new DefaultProjectBuilder(); | |||
| m_builder.enableLogging( createLogger() ); | |||
| m_builder.enableLogging( getLogger() ); | |||
| } | |||
| /** | |||
| * Test validation of project and target names. | |||
| * Creates a project, with default values set. | |||
| */ | |||
| private DefaultProject createProject( final File projFile ) | |||
| { | |||
| final DefaultProject project = new DefaultProject(); | |||
| project.setProjectName( FileUtil.removeExtension( projFile.getName() ) ); | |||
| project.setBaseDirectory( getTestDirectory( "." ) ); | |||
| project.setDefaultTargetName( "main" ); | |||
| return project; | |||
| } | |||
| /** | |||
| * Tests bad project file name. | |||
| */ | |||
| public void testProjectFileName() throws Exception | |||
| { | |||
| // Test with a file that does not exist | |||
| File projFile = getTestResource( "unknown.ant", false ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.no-project-file.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| // Test with a directory | |||
| projFile = getTestDirectory( "some-dir" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.no-project-file.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| } | |||
| /** | |||
| * Tests error reporting when the project file contains badly formed XML. | |||
| */ | |||
| public void testBadlyFormedFile() throws Exception | |||
| { | |||
| final File projFile = getTestResource( "bad-xml.ant" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.project-parse.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| } | |||
| /** | |||
| * Tests building a project with default values for project name, base dir | |||
| * and default target. | |||
| */ | |||
| public void testDefaults() throws Exception | |||
| { | |||
| // Build project | |||
| final File projFile = getTestResource( "defaults.ant" ); | |||
| Project project = m_builder.build( projFile.getAbsolutePath() ); | |||
| // Compare against expected project | |||
| DefaultProject expected = createProject( projFile ); | |||
| assertSameProject( expected, project ); | |||
| } | |||
| /** | |||
| * Tests setting the project name. | |||
| */ | |||
| public void testProjectName() throws Exception | |||
| { | |||
| // Build project | |||
| final File projFile = getTestResource( "set-project-name.ant" ); | |||
| Project project = m_builder.build( projFile.getAbsolutePath() ); | |||
| // Compare against expected project | |||
| DefaultProject expected = createProject( projFile ); | |||
| expected.setProjectName( "some-project" ); | |||
| assertSameProject( expected, project ); | |||
| } | |||
| /** | |||
| * Tests setting the base directory. | |||
| */ | |||
| public void testBaseDirectory() throws Exception | |||
| { | |||
| // Build project | |||
| final File projFile = getTestResource( "set-base-dir.ant" ); | |||
| Project project = m_builder.build( projFile.getAbsolutePath() ); | |||
| // Compare against expected project | |||
| DefaultProject expected = createProject( projFile ); | |||
| final File baseDir = getTestDirectory( "other-base-dir" ); | |||
| expected.setBaseDirectory( baseDir ); | |||
| assertSameProject( expected, project ); | |||
| } | |||
| /** | |||
| * Tests setting the default target name. | |||
| */ | |||
| public void testDefaultTarget() throws Exception | |||
| { | |||
| // Build project | |||
| final File projFile = getTestResource( "set-default-target.ant" ); | |||
| Project project = m_builder.build( projFile.getAbsolutePath() ); | |||
| // Compare against expected project | |||
| DefaultProject expected = createProject( projFile ); | |||
| expected.setDefaultTargetName( "some-target" ); | |||
| assertSameProject( expected, project ); | |||
| } | |||
| /** | |||
| * Tests missing, invalid and incompatible project version. | |||
| */ | |||
| public void testProjectVersion() throws Exception | |||
| { | |||
| // No version | |||
| File projFile = getTestResource( "no-version.ant" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.version-missing.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| // Badly formed version | |||
| projFile = getTestResource( "bad-version.ant" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.malformed.version", "ant2" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| // Incompatible version | |||
| projFile = getTestResource( "mismatched-version.ant" ); | |||
| try | |||
| { | |||
| m_builder.build( projFile.getAbsolutePath() ); | |||
| fail(); | |||
| } | |||
| catch( ProjectException e ) | |||
| { | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", projFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.bad-version.error", "2.0.0", "1.0.2" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| } | |||
| /** | |||
| * Asserts that 2 projects are identical. | |||
| */ | |||
| protected void assertSameProject( final Project expected, | |||
| final Project project ) | |||
| { | |||
| assertEquals( expected.getProjectName(), project.getProjectName() ); | |||
| assertEquals( expected.getBaseDirectory(), project.getBaseDirectory() ); | |||
| assertEquals( expected.getDefaultTargetName(), project.getDefaultTargetName() ); | |||
| // TODO - make sure each of the projects are the same | |||
| assertTrue( Arrays.equals( expected.getProjectNames(), project.getProjectNames() ) ); | |||
| // TODO - make sure the implicit targets are the same | |||
| // TODO - make sure each of the targets are the same | |||
| assertTrue( Arrays.equals( expected.getTargetNames(), project.getTargetNames() ) ); | |||
| // TODO - implement TypeLib.equals(), or use a comparator | |||
| assertTrue( Arrays.equals( expected.getTypeLibs(), project.getTypeLibs() ) ); | |||
| } | |||
| /** | |||
| * Tests validation of project and target names. | |||
| */ | |||
| public void testNameValidation() throws Exception | |||
| { | |||
| @@ -52,7 +272,12 @@ public class DefaultProjectBuilderTest | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| assertSameMessage( REZ.getString( "ant.project-bad-name.error" ), e ); | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", badProjectFile.getAbsolutePath() ), | |||
| REZ.getString( "ant.project-bad-name.error" ) | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| // Check bad target name | |||
| @@ -64,7 +289,13 @@ public class DefaultProjectBuilderTest | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| // TODO - check error message | |||
| final String[] messages = | |||
| { | |||
| REZ.getString( "ant.project-build.error", badTargetFile.getAbsolutePath() ), | |||
| // TODO - check error message | |||
| null | |||
| }; | |||
| assertSameMessage( messages, e ); | |||
| } | |||
| } | |||
| } | |||
| @@ -5,53 +5,51 @@ | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.myrmidon.components.workspace; | |||
| package org.apache.myrmidon.components.property; | |||
| import java.io.File; | |||
| import java.util.Date; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.avalon.framework.context.Context; | |||
| import org.apache.myrmidon.AbstractMyrmidonTest; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.myrmidon.components.AbstractComponentTest; | |||
| import org.apache.myrmidon.components.property.DefaultPropertyResolver; | |||
| import org.apache.myrmidon.components.workspace.DefaultTaskContext; | |||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
| /** | |||
| * Functional tests for {@link DefaultPropertyResolver}. | |||
| * General-purpose property resolver test cases. | |||
| * | |||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class DefaultPropertyResolverTest | |||
| extends AbstractComponentTest | |||
| public abstract class AbstractPropertyResolverTest | |||
| extends AbstractMyrmidonTest | |||
| { | |||
| protected final static Resources REZ | |||
| = ResourceManager.getPackageResources( DefaultPropertyResolver.class ); | |||
| = ResourceManager.getPackageResources( AbstractPropertyResolverTest.class ); | |||
| protected PropertyResolver m_resolver; | |||
| protected DefaultTaskContext m_context; | |||
| public DefaultPropertyResolverTest( String name ) | |||
| public AbstractPropertyResolverTest( String name ) | |||
| { | |||
| super( name ); | |||
| } | |||
| protected void setUp() throws Exception | |||
| { | |||
| super.setUp(); | |||
| m_resolver = createResolver(); | |||
| m_context = new DefaultTaskContext( null, getServiceManager(), getLogger() ); | |||
| m_context = new DefaultTaskContext( null, null, getLogger() ); | |||
| m_context.setProperty( "intProp", new Integer( 333 ) ); | |||
| m_context.setProperty( "stringProp", "String property" ); | |||
| } | |||
| protected PropertyResolver createResolver() | |||
| { | |||
| return new DefaultPropertyResolver(); | |||
| } | |||
| /** | |||
| * Creates the resolver to test. | |||
| */ | |||
| protected abstract PropertyResolver createResolver(); | |||
| /** | |||
| * Test property resolution with various different typed properties. | |||
| @@ -73,7 +71,7 @@ public class DefaultPropertyResolverTest | |||
| throws Exception | |||
| { | |||
| m_context.setProperty( "typedProp", propObject ); | |||
| String propString = propObject.toString(); | |||
| final String propString = propObject.toString(); | |||
| doTestResolution( "${typedProp}", propObject, m_context ); | |||
| doTestResolution( "${typedProp} with following text", | |||
| @@ -96,23 +94,6 @@ public class DefaultPropertyResolverTest | |||
| doTestResolution( "before ${prop2} between ${prop1} after", | |||
| "before value2 between value1 after", m_context ); | |||
| doTestResolution( "${prop1}-${int1}-${prop2}", "value1-123-value2", m_context ); | |||
| } | |||
| /** | |||
| * Tests handing undefined property. | |||
| */ | |||
| public void testUndefinedProp() throws Exception | |||
| { | |||
| String undefinedProp = "undefinedProperty"; | |||
| doTestFailure( "${" + undefinedProp + "}", | |||
| REZ.getString( "prop.missing-value.error", undefinedProp ), | |||
| m_context ); | |||
| //TODO - "" should be disallowed as a property name | |||
| doTestFailure( "${}", | |||
| REZ.getString( "prop.missing-value.error", "" ), | |||
| m_context ); | |||
| } | |||
| /** | |||
| @@ -131,18 +112,17 @@ public class DefaultPropertyResolverTest | |||
| /* TODO - need to handle these cases. */ | |||
| // testFailure( "${bad${}", "", m_context ); | |||
| // testFailure( "${ }", "", m_context ); | |||
| } | |||
| /** | |||
| * Resolves the property using the supplied context, and checks the result. | |||
| */ | |||
| protected void doTestResolution( String value, | |||
| Object expected, | |||
| Context context ) | |||
| protected void doTestResolution( final String value, | |||
| final Object expected, | |||
| final Context context ) | |||
| throws Exception | |||
| { | |||
| Object resolved = m_resolver.resolveProperties( value, context ); | |||
| final Object resolved = m_resolver.resolveProperties( value, context ); | |||
| assertEquals( expected, resolved ); | |||
| } | |||
| @@ -151,9 +131,9 @@ public class DefaultPropertyResolverTest | |||
| * Attempts to resolve the value using the supplied context, expecting to | |||
| * fail with the supplied error message. | |||
| */ | |||
| protected void doTestFailure( String value, | |||
| String expectedErrorMessage, | |||
| Context context ) | |||
| protected void doTestFailure( final String value, | |||
| final String expectedErrorMessage, | |||
| final Context context ) | |||
| { | |||
| try | |||
| { | |||
| @@ -5,19 +5,18 @@ | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.myrmidon.components.workspace; | |||
| package org.apache.myrmidon.components.property; | |||
| import org.apache.myrmidon.interfaces.property.PropertyResolver; | |||
| import org.apache.myrmidon.components.property.ClassicPropertyResolver; | |||
| /** | |||
| * A test for {@link ClassicPropertyResolver} | |||
| * A test for {@link ClassicPropertyResolver}. | |||
| * | |||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class ClassicPropertyResolverTest | |||
| extends DefaultPropertyResolverTest | |||
| extends AbstractPropertyResolverTest | |||
| { | |||
| public ClassicPropertyResolverTest( String name ) | |||
| { | |||
| @@ -34,8 +33,7 @@ public class ClassicPropertyResolverTest | |||
| */ | |||
| public void testUndefinedProp() throws Exception | |||
| { | |||
| String undefinedProp = "undefinedProperty"; | |||
| final String undefinedProp = "undefinedProperty"; | |||
| final String propRef = "${" + undefinedProp + "}"; | |||
| doTestResolution( propRef, propRef, m_context ); | |||
| } | |||
| @@ -0,0 +1,46 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache 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; | |||
| /** | |||
| * Functional tests for {@link DefaultPropertyResolver}. | |||
| * | |||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||
| * @version $Revision$ $Date$ | |||
| */ | |||
| public class DefaultPropertyResolverTest | |||
| extends AbstractPropertyResolverTest | |||
| { | |||
| public DefaultPropertyResolverTest( String name ) | |||
| { | |||
| super( name ); | |||
| } | |||
| protected PropertyResolver createResolver() | |||
| { | |||
| return new DefaultPropertyResolver(); | |||
| } | |||
| /** | |||
| * Tests handing undefined property. | |||
| */ | |||
| public void testUndefinedProp() throws Exception | |||
| { | |||
| final String undefinedProp = "undefinedProperty"; | |||
| doTestFailure( "${" + undefinedProp + "}", | |||
| REZ.getString( "prop.missing-value.error", undefinedProp ), | |||
| m_context ); | |||
| //TODO - "" should be disallowed as a property name | |||
| doTestFailure( "${}", | |||
| REZ.getString( "prop.missing-value.error", "" ), | |||
| m_context ); | |||
| } | |||
| } | |||
| @@ -44,11 +44,9 @@ public class InstantiatingServiceManagerTest | |||
| protected void setUp() | |||
| throws Exception | |||
| { | |||
| super.setUp(); | |||
| // Set-up the service manager | |||
| m_serviceManager = new InstantiatingServiceManager(); | |||
| m_serviceManager.enableLogging( createLogger() ); | |||
| m_serviceManager.enableLogging( getLogger() ); | |||
| m_serviceManager.service( getServiceManager() ); | |||
| m_serviceManager.parameterize( m_parameters ); | |||
| } | |||