Package com.cedarsoft.maven.instrumentation.plugin

Source Code of com.cedarsoft.maven.instrumentation.plugin.ClassFile

package com.cedarsoft.maven.instrumentation.plugin;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.LoaderClassPath;

import javax.annotation.Nonnull;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;

/**
* @author Johannes Schneider (<a href="mailto:js@cedarsoft.com">js@cedarsoft.com</a>)
*/
public class ClassFile {
  @Nonnull
  private final File classFile;
  @Nonnull
  private final CtClass compiledClass;

  public ClassFile( @Nonnull final File classFile, @Nonnull ClassLoader classLoader ) throws IOException {
    this.classFile = classFile;
    final ClassPool cp = ClassPool.getDefault();
    cp.appendClassPath( new LoaderClassPath( classLoader ) );

    final InputStream ins = new BufferedInputStream( new FileInputStream( classFile ) );
    try {
      compiledClass = cp.makeClass( ins );
    } finally {
      ins.close();
    }
  }

  @Nonnull
  public String getClassName() {
    return compiledClass.getName();
  }

  public void transform( @Nonnull final ClassFileTransformer agent ) throws ClassTransformationException {
    try {
      doTransform( agent );
    } catch ( final MalformedURLException e ) {
      throw new RuntimeException( "Should not happen.  Could not create URL from file.", e );
    } catch ( final IOException e ) {
      throw new ClassTransformationException( "Failed to write transformed class file contents.", e );
    } catch ( final CannotCompileException e ) {
      throw new RuntimeException( "Should not happen. Failed to convert a valid compiled class into bytecode", e );
    } catch ( final IllegalClassFormatException e ) {
      throw new RuntimeException( "Should not happen.  The class file does not contain valid content", e );
    }
  }

  private void doTransform( @Nonnull final ClassFileTransformer agent ) throws MalformedURLException, CannotCompileException, IOException,
    IllegalClassFormatException {
    final ClassLoader loader = getClassLoader();
    final String className = getInternalClassName();
    final Class<?> classBeingRedefined = compiledClass.toClass( loader, loader.getClass().getProtectionDomain() );
    final byte[] classBytes = compiledClass.toBytecode();
    final ProtectionDomain protectionDomain = classBeingRedefined.getProtectionDomain();

    final byte[] transformedBytes = agent.transform( loader, className, classBeingRedefined, protectionDomain, classBytes );

    replaceClassContents( transformedBytes );
  }

  @Nonnull
  private ClassLoader getClassLoader() throws MalformedURLException {
    final File parentDir = getClassParentDir();
    return new URLClassLoader( new URL[]{parentDir.toURI().toURL()} );
  }

  @Nonnull
  public File getClassParentDir() {
    final String className = compiledClass.getName();
    final int packageCount = className.split( "\\." ).length;
    File parentDir = classFile;
    for ( int i = 0; i < packageCount; i++ ) {
      parentDir = parentDir.getParentFile();
    }
    return parentDir;
  }

  /**
   * @return The internal class name as specified in the JVM Specification
   *
   * @see http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html
   */
  @Nonnull
  private String getInternalClassName() {
    return compiledClass.getName().replace( '.', '/' );
  }

  private void replaceClassContents( @Nonnull final byte[] replacementBytes ) throws IOException {
    final BufferedOutputStream bufferedStream = new BufferedOutputStream( new FileOutputStream( classFile ) );
    try {
      bufferedStream.write( replacementBytes );
      bufferedStream.flush();
    } finally {
      bufferedStream.close();
    }
  }

  @Override
  public String toString() {
    return "ClassFile [classFile=" + classFile + "]";
  }
}
TOP

Related Classes of com.cedarsoft.maven.instrumentation.plugin.ClassFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.