package org.codehaus.mojo.mant; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Resource; import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.dom4j.DocumentException; /** * Class to handle execution of an ant task. * For an optional task a taskdef will be created using * a constructor supplied class and the dependecies for the * corresponding classpath. * A build.xml temp file is created and executed with the ant * api. */ public class MantGoal { public static final String JAVA = "JAVA"; public static final String RES = "RES"; public static final String JAVA_GEN = "JAVA_GEN"; public static final String RES_GEN = "RES_GEN"; public static final String WEB_INF_GEN = "WEB_INF_GEN"; public static final String META_INF_GEN = "META_INF_GEN"; private final MavenProject project; private final Mojo mojo; private String taskdefClass; private String task; private String[] mappings; private List classpath; private HashMap replacements; /** * Creates this goal using the given mojo and project information. * Also supplied is the xml task to be run along with the mappings that * specify which maven property to be substituted for the ant attribute. * If the task is optional then the a non null taskdef class may be passed in. * @param mojo * @param project * @param taskdefClass * @param task * @param mappings */ public MantGoal( Mojo mojo, MavenProject project, String taskdefClass, String task, String[] mappings ) { this.mojo = mojo; this.project = project; this.taskdefClass = taskdefClass; this.task = task; this.replacements = createReplacements(); this.mappings = createMappings(mappings); this.classpath = createClasspath(); } /** * Fills up the replacements map. * @return */ private HashMap createReplacements() { HashMap constants = new HashMap(); constants.put(JAVA, new File(project.getBasedir(), "src/main/java").getPath()); constants.put(RES, new File(project.getBasedir(), "src/main/resources").getPath()); constants.put(JAVA_GEN, new File(project.getBuild().getDirectory(), "generated/src/main/java").getPath()); constants.put(RES_GEN, new File(project.getBuild().getDirectory(), "generated/src/main/resources").getPath()); constants.put(WEB_INF_GEN, new File(project.getBuild().getDirectory(), "generated/src/main/resources/WEB-INF").getPath()); constants.put(META_INF_GEN, new File(project.getBuild().getDirectory(), "generated/src/main/resources/META-INF").getPath()); return constants; } /** * Replaces the tokens in the mappings with their actual maven values. * For example if a maven value is "JAVA" it might be replaced * by "/Users/proj/src/main/java", known only at runtime, as they depend * on the current project object. * @param mappings * @return */ private String[] createMappings(String[] mappings) { for ( int i = 1; i < mappings.length; i += 2 ) { String mavenProperty = mappings[i]; mappings[i] = (String) replacements.get(mavenProperty); } return mappings; } /** * Executes the ant task whilst the given system property has the classpath string set. * This is really just to support xdoclet that for some reason doesn't work with taskdef classpath. * @param classpathProperty TODO * @throws MojoExecutionException * @throws DocumentException * @throws Exception */ public void execute(String classpathProperty) throws MojoExecutionException { String value = getClasspathString(); mojo.getLog().info("setting the following system property:"); mojo.getLog().info(classpathProperty); mojo.getLog().info(value); System.setProperty( classpathProperty, value ); execute(); System.getProperties().remove( classpathProperty ); } /** * Executes the underlying ant task. * @throws MojoExecutionException */ public void execute() throws MojoExecutionException { try { executeTask(); updateProject(); } catch ( Exception e ) { throw new MojoExecutionException("goal failed", e); } } /** * Executes the ant task by creating the build.xml file and running it through ant. * @throws Exception */ public void executeTask() throws Exception { AntTask antTask = new AntTask( task, mappings ); AntDocument antDocument = new AntDocument( project.getBasedir().getPath(), taskdefClass, classpath, antTask.getTask() ); AntProject antProject = new AntProject( antDocument.getDocument() ); mojo.getLog().info( antProject.toString() ); antProject.execute(); } /** * Updates the resource and sources project directories to reflect generated code. * */ public void updateProject() { project.addCompileSourceRoot( getJavaGen() ); Resource resource = new Resource(); resource.setDirectory( getResGen() ); project.addResource( resource ); } /** * Creates the taskdef classpath from the project artifact dependencies. * @return */ private List createClasspath() { ArrayList classpath = new ArrayList(); Iterator allArtifacts = project.getArtifacts().iterator(); while ( allArtifacts.hasNext() ) { Artifact artifact = (Artifact) allArtifacts.next(); classpath.add( artifact.getFile().getPath() ); } return classpath; } /** * Gets the classpath as a single string and always has a colon * (or OS equivalent) on the end, when non empty. * @return */ public String getClasspathString() { StringBuffer pathString = new StringBuffer(); ListIterator allPaths = classpath.listIterator(); while ( allPaths.hasNext() ) { String path = (String) allPaths.next(); pathString.append(path); pathString.append(File.pathSeparatorChar); } return pathString.toString(); } public String getJava() { return (String) replacements.get(JAVA); } public String getRes() { return (String) replacements.get(RES); } public String getJavaGen() { return (String) replacements.get(JAVA_GEN); } public String getResGen() { return (String) replacements.get(RES_GEN); } public String getWebInfGen() { return (String) replacements.get(WEB_INF_GEN); } public String getMetaInfGen() { return (String) replacements.get(META_INF_GEN); } }