All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.maven.plugins.retro.WeaveMojo Maven / Gradle / Ivy

package org.jboss.maven.plugins.retro;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.Deflater;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.jboss.weaver.WeaveRunner;
import org.jboss.weaver.Weaver;

/**
 * Maven plugin for JBoss Retro Weaver.  This can be used to 
 * do byte code weaving on classes in jars and directories.
 * By default the weaver will weave the main classes
 * and output the result to a jar with the specified classifier.
 * 
 * @phase process-classes
 * @goal weave
 * 
 */
public class WeaveMojo extends AbstractMojo
{
   public static final String JBOSS_RETRO_ARTIFACTID = "jboss-retro";
   
   protected final String fileSep = System.getProperty("file.separator");

   protected final String pathSep = System.getProperty("path.separator");

   /**
    * List of the jar file entries
    */
   private ArrayList fileEntries = new ArrayList();

   /**
    * The Maven Project Object
    *
    * @parameter expression="${project}"
    * @required
    * @readonly
    */
   protected MavenProject project;

   /**
    * The Maven Project Helper Object
    *
    * @component
    * @required
    * @readonly
    */
   protected org.apache.maven.project.MavenProjectHelper projectHelper;

   /**
    * The plugin dependencies.
    *
    * @parameter expression="${plugin.artifacts}"
    * @required
    * @readonly
    */
   protected List pluginArtifacts;

   /**
    * Project classpath.
    *
    * @parameter expression="${project.compileClasspathElements}"
    * @required
    * @readonly
    */
   protected List classpathElements;
   
   /**
    * The directory for compiled classes.
    *
    * @parameter expression="${project.build.outputDirectory}"
    * @required
    */
   protected File classesDirectory;

   /**
    * Include verbose output.
    * @parameter
    */
   protected boolean verbose = false;

   /**
    * The Weaver class to use for weaving the classes.
    * Defaults to org.jboss.weaver.Weaver
    * Any subclass of org.jboss.weaver.Weaver can be used
    * 
    * @parameter
    */
   protected String weaverClass = "org.jboss.weaver.Weaver";

   /**
    * The jar file or directory where the weaved classes
    * should be written.  The path is relative to the project
    * output directory (target).
    * Defaults to "target/classes-weaved"
    * @parameter
    */
   protected String weaverOutputPath;
   
   /**
    * Create weaved jar.
    * @parameter
    */
   protected boolean createJar = true;
   
   /**
    * Classifier to append to the weaved output file.
    * Defaults to "weaved".
    * @parameter
    */
   protected String weaveClassifier = "weaved";
   
   /**
    * Suppress output information.
    * @parameter
    */
   protected boolean suppress = true;

   /**
    * Main plugin execution method
    */   
   public void execute() throws MojoFailureException
   {
      this.getLog().info("Weaving classes in: " + this.getClassesDirecotry());
      long start = System.currentTimeMillis();
      
      weaveClasses();
      
      long end = System.currentTimeMillis();
      this.getLog().info("Weaving complete: " + (end - start) + "ms");
   }
   
   protected void weaveClasses() throws MojoFailureException {
      // Initialize the WeaveRunner using plugin params
      Weaver weaver = createWeaver();
      weaver.setClasspath(this.buildClasspath());
      weaver.init();
      WeaveRunner weaveRunner = new WeaveRunner(weaver);

      weaveRunner.setVerbose(verbose);
      weaveRunner.setSuppress(suppress);
      weaveRunner.setUsingSystemClasspath(false);
      
      weaveRunner.setOutputPath(getOutputPath()); 
      
      try
      {
         weaveRunner.addSourcePath(this.getClassesDirecotry().getAbsolutePath());
         weaveRunner.weave();
      }
      catch (Exception e)
      {
         this.getLog().error(e);
         e.printStackTrace();
      }
   }
   
   /**
    * Generates a classpath string based on the compile class path
    * and the plugin dependencies.
    * @return
    */
   protected String buildClasspath() {
      StringBuilder classpath = new StringBuilder();

      List cpElements = this.getClasspathElements();
      for (Object element : cpElements)
      {
         classpath.append(element);
         classpath.append(pathSep);
      }
      
      // If the weaver classes can be found in the source directory 
      // (i.e. we are weaving jboss retro), then we don't want the 
      // retro jar from the plugin dependency to be pulled in from the repo.
      boolean useRetroDep = true;
      NameFileFilter nameFilter = new NameFileFilter("Weaver.class");
      Collection weaverClassFiles = FileUtils.listFiles(this.getClassesDirecotry(), nameFilter, TrueFileFilter.INSTANCE);
      if (weaverClassFiles.size() > 0)
      {
         useRetroDep = false;
      }
      
      for (Object artifactObj : pluginArtifacts)
      {
         try
         {
            Artifact artifact = (Artifact) artifactObj;
            if (artifact.getFile() != null)
            {
               if ( useRetroDep || ( ! artifact.getArtifactId().equals(JBOSS_RETRO_ARTIFACTID)))
               {
                  classpath.append(artifact.getFile().getCanonicalPath());
                  classpath.append(pathSep);
               }
            }
         }
         catch (IOException ioe)
         {
            this.getLog().warn("Could not get filename");
         }
      }
      return classpath.toString();
   }
      
   /**
    * This method creates the weaver instance.  Subclass mojos
    * can use this class to override the default weaver configuration.
    * @return The weaver instance
    */
   protected Weaver createWeaver() throws MojoFailureException {
      // We have to set the classpath first because the initialization
      // may require access to the classpath.
      Weaver weaver = null;

      try {
         weaver = (Weaver)Class.forName(weaverClass).newInstance();
      } catch (Exception e) {
         getLog().error("Unable to instantiate weaver class: " + this.weaverClass);
         getLog().error(e.getMessage());
         throw new MojoFailureException(e.getMessage());
      }
      
      return weaver;
   }

   private void createJarEntries(File retroClassesDir)
   {
      try
      {
         this.getLog().info("DEBUG: " + retroClassesDir.getAbsolutePath());
         Collection retroClasses = FileUtils.listFiles(retroClassesDir, null, true);
         for (Object classFile : retroClasses)
         {
            String relativePath = classFile.toString().replace(retroClassesDir.getAbsolutePath() + "/", "");
            byte[] content = FileUtils.readFileToByteArray((File) classFile);
            fileEntries.add(new JarFileEntry(relativePath, content));
         }
      }
      catch (IOException ioe)
      {
         this.getLog().error("error reading class file: " + ioe);
      }
   }

   private void createRetroJarFile(File retroJarFile)
   {
      try
      {
         Manifest manifest = new Manifest();
         Attributes attributes = manifest.getMainAttributes();
         attributes.putValue("Manifest-Version", "1.0");
         attributes.putValue("Created-By", System.getProperty("java.vm.version") + " ("
               + System.getProperty("java.vm.vendor") + ")");
         JarOutputStream stream = new JarOutputStream(new FileOutputStream(retroJarFile), manifest);
         stream.setLevel(Deflater.BEST_COMPRESSION);
         for (JarFileEntry fileEntry : fileEntries)
         {
            JarEntry jarEntry = new JarEntry(fileEntry.getName());
            stream.putNextEntry(jarEntry);
            stream.write(fileEntry.getContent());
         }
         stream.close();
      }
      catch (IOException ioe)
      {
         this.getLog().error("Unable to write retro jar: " + ioe);
      }
   }

   protected static class JarFileEntry
   {

      private byte[] content;

      private String name;

      public JarFileEntry(String name, byte[] content)
      {
         this.name = name;
         this.content = content;
      }

      public byte[] getContent()
      {
         return content;
      }

      public String getName()
      {
         return name;
      }

      public void setName(String name)
      {
         this.name = name;
      }
   }
   
   protected String getOutputPath() 
   {
      if (this.weaverOutputPath == null) {
         String classesDirString = getClassesDirecotry().getAbsolutePath();
         if(classesDirString.endsWith(this.fileSep)) {
            classesDirString = classesDirString.substring(0, (classesDirString.length() - 2));
         }
         return (classesDirectory + "-" + this.weaveClassifier);
      }
      else 
      {
         String buildDirectory = project.getBuild().getDirectory();
         if (!buildDirectory.endsWith(fileSep)) {
            buildDirectory += fileSep;
         }
         return buildDirectory + this.fileSep + this.weaverOutputPath;
      }
   }
   
   public List getClasspathElements() {
      return this.classpathElements;
   }
   
   public File getClassesDirecotry() {
      return this.classesDirectory;
   }
   
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy