[hibernate-commits] Hibernate SVN: r16068 - in core/branches/Branch_3_3: core/src/main/java/org/hibernate/bytecode and 11 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Mar 3 21:20:50 EST 2009


Author: steve.ebersole at jboss.com
Date: 2009-03-03 21:20:50 -0500 (Tue, 03 Mar 2009)
New Revision: 16068

Added:
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/AbstractInstrumenter.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/CGLIBInstrumenter.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/ExecutionException.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/Instrumenter.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/JavassistInstrumenter.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/Logger.java
   core/branches/Branch_3_3/hibernate-maven-plugin/
   core/branches/Branch_3_3/hibernate-maven-plugin/pom.xml
   core/branches/Branch_3_3/hibernate-maven-plugin/src/
   core/branches/Branch_3_3/hibernate-maven-plugin/src/main/
   core/branches/Branch_3_3/hibernate-maven-plugin/src/main/java/
   core/branches/Branch_3_3/hibernate-maven-plugin/src/main/java/org/
   core/branches/Branch_3_3/hibernate-maven-plugin/src/main/java/org/hibernate/
   core/branches/Branch_3_3/hibernate-maven-plugin/src/main/java/org/hibernate/maven/
   core/branches/Branch_3_3/hibernate-maven-plugin/src/main/java/org/hibernate/maven/InstrumentationMojo.java
Modified:
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/BasicInstrumentationTask.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/cglib/InstrumentTask.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java
   core/branches/Branch_3_3/pom.xml
Log:
HHH-3279 : maven plugin (initial work)

Added: core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/AbstractInstrumenter.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/AbstractInstrumenter.java	                        (rev 0)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/AbstractInstrumenter.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -0,0 +1,443 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.bytecode.buildtime;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import java.util.zip.CRC32;
+import java.io.File;
+import java.io.DataInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+
+import org.hibernate.bytecode.util.ByteCodeHelper;
+import org.hibernate.bytecode.util.ClassDescriptor;
+import org.hibernate.bytecode.util.FieldFilter;
+import org.hibernate.bytecode.ClassTransformer;
+
+/**
+ * Provides the basic templating of how instrumentation should occur.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractInstrumenter implements Instrumenter {
+	private static final int ZIP_MAGIC = 0x504B0304;
+	private static final int CLASS_MAGIC = 0xCAFEBABE;
+	
+	protected final Logger logger;
+	protected final Options options;
+
+	/**
+	 * Creates the basic instrumentation strategy.
+	 *
+	 * @param logger The bridge to the environment's logging system.
+	 * @param options User-supplied options.
+	 */
+	public AbstractInstrumenter(Logger logger, Options options) {
+		this.logger = logger;
+		this.options = options;
+	}
+
+	/**
+	 * Given the bytecode of a java class, retrieve the descriptor for that class.
+	 *
+	 * @param byecode The class bytecode.
+	 *
+	 * @return The class's descriptor
+	 *
+	 * @throws Exception Indicates problems access the bytecode.
+	 */
+	protected abstract ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception;
+
+	/**
+	 * Create class transformer for the class.
+	 *
+	 * @param descriptor The descriptor of the class to be instrumented.
+	 * @param classNames The names of all classes to be instrumented; the "pipeline" if you will.
+	 *
+	 * @return The transformer for the given class; may return null to indicate that transformation should
+	 * be skipped (ala already instrumented).
+	 */
+	protected abstract ClassTransformer getClassTransformer(ClassDescriptor descriptor, Set classNames);
+
+	/**
+	 * The main instrumentation entry point.  Given a set of files, perform instrumentation on each discovered class
+	 * file.
+	 *
+	 * @param files The files.
+	 */
+	public void execute(Set files) {
+		Set classNames = new HashSet();
+
+		if ( options.performExtendedInstrumentation() ) {
+			logger.debug( "collecting class names for extended instrumentation determination" );
+			try {
+				Iterator itr = files.iterator();
+				while ( itr.hasNext() ) {
+					final File file = ( File ) itr.next();
+					collectClassNames( file, classNames );
+				}
+			}
+			catch ( ExecutionException ee ) {
+				throw ee;
+			}
+			catch ( Exception e ) {
+				throw new ExecutionException( e );
+			}
+		}
+
+		logger.info( "starting instrumentation" );
+		try {
+			Iterator itr = files.iterator();
+			while ( itr.hasNext() ) {
+				final File file = ( File ) itr.next();
+				processFile( file, classNames );
+			}
+		}
+		catch ( ExecutionException ee ) {
+			throw ee;
+		}
+		catch ( Exception e ) {
+			throw new ExecutionException( e );
+		}
+	}
+
+	/**
+	 * Extract the names of classes from file, addding them to the classNames collection.
+	 * <p/>
+	 * IMPL NOTE : file here may be either a class file or a jar.  If a jar, all entries in the jar file are
+	 * processed.
+	 *
+	 * @param file The file from which to extract class metadata (descriptor).
+	 * @param classNames The collected class name collection.
+	 *
+	 * @throws Exception indicates problems accessing the file or its contents.
+	 */
+	private void collectClassNames(File file, final Set classNames) throws Exception {
+	    if ( isClassFile( file ) ) {
+			byte[] bytes = ByteCodeHelper.readByteCode( file );
+			ClassDescriptor descriptor = getClassDescriptor( bytes );
+		    classNames.add( descriptor.getName() );
+	    }
+	    else if ( isJarFile( file ) ) {
+		    ZipEntryHandler collector = new ZipEntryHandler() {
+			    public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
+					if ( !entry.isDirectory() ) {
+						// see if the entry represents a class file
+						DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
+						if ( din.readInt() == CLASS_MAGIC ) {
+				            classNames.add( getClassDescriptor( byteCode ).getName() );
+						}
+					}
+			    }
+		    };
+			ZipFileProcessor processor = new ZipFileProcessor( collector );
+		    processor.process( file );
+	    }
+	}
+
+	/**
+	 * Does this file represent a compiled class?
+	 *
+	 * @param file The file to check.
+	 *
+	 * @return True if the file is a class; false otherwise.
+	 *
+	 * @throws IOException Indicates problem access the file.
+	 */
+	protected final boolean isClassFile(File file) throws IOException {
+        return checkMagic( file, CLASS_MAGIC );
+    }
+
+	/**
+	 * Does this file represent a zip file of some format?
+	 *
+	 * @param file The file to check.
+	 *
+	 * @return True if the file is n archive; false otherwise.
+	 *
+	 * @throws IOException Indicates problem access the file.
+	 */
+    protected final boolean isJarFile(File file) throws IOException {
+        return checkMagic(file, ZIP_MAGIC);
+    }
+
+	protected final boolean checkMagic(File file, long magic) throws IOException {
+        DataInputStream in = new DataInputStream( new FileInputStream( file ) );
+        try {
+            int m = in.readInt();
+            return magic == m;
+        }
+        finally {
+            in.close();
+        }
+    }
+
+	/**
+	 * Actually process the file by applying instrumentation transformations to any classes it contains.
+	 * <p/>
+	 * Again, just like with {@link #collectClassNames} this method can handle both class and archive files.
+	 *
+	 * @param file The file to process.
+	 * @param classNames The 'pipeline' of classes to be processed.  Only actually populated when the user
+	 * specifies to perform {@link Options#performExtendedInstrumentation() extended} instrumentation.
+	 *
+	 * @throws Exception Indicates an issue either access files or applying the transformations.
+	 */
+	protected void processFile(File file, Set classNames) throws Exception {
+	    if ( isClassFile( file ) ) {
+			logger.debug( "processing class file : " + file.getAbsolutePath() );
+	        processClassFile( file, classNames );
+	    }
+	    else if ( isJarFile( file ) ) {
+			logger.debug( "processing jar file : " + file.getAbsolutePath() );
+	        processJarFile( file, classNames );
+	    }
+	    else {
+		    logger.debug( "ignoring file : " + file.getAbsolutePath() );
+	    }
+	}
+
+	/**
+	 * Process a class file.  Delegated to from {@link #processFile} in the case of a class file.
+	 *
+	 * @param file The class file to process.
+	 * @param classNames The 'pipeline' of classes to be processed.  Only actually populated when the user
+	 * specifies to perform {@link Options#performExtendedInstrumentation() extended} instrumentation.
+	 *
+	 * @throws Exception Indicates an issue either access files or applying the transformations.
+	 */
+	protected void processClassFile(File file, Set classNames) throws Exception {
+		byte[] bytes = ByteCodeHelper.readByteCode( file );
+		ClassDescriptor descriptor = getClassDescriptor( bytes );
+		ClassTransformer transformer = getClassTransformer( descriptor, classNames );
+		if ( transformer == null ) {
+			logger.debug( "no trasformer for class file : " + file.getAbsolutePath() );
+			return;
+		}
+
+		logger.info( "processing class : " + descriptor.getName() + ";  file = " + file.getAbsolutePath() );
+		byte[] transformedBytes = transformer.transform(
+				getClass().getClassLoader(),
+				descriptor.getName(),
+				null,
+				null,
+				descriptor.getBytes()
+		);
+
+		OutputStream out = new FileOutputStream( file );
+		try {
+			out.write( transformedBytes );
+			out.flush();
+		}
+		finally {
+			try {
+				out.close();
+			}
+			catch ( IOException ignore) {
+				// intentionally empty
+			}
+		}
+	}
+
+	/**
+	 * Process an archive file.  Delegated to from {@link #processFile} in the case of an archive file.
+	 *
+	 * @param file The archive file to process.
+	 * @param classNames The 'pipeline' of classes to be processed.  Only actually populated when the user
+	 * specifies to perform {@link Options#performExtendedInstrumentation() extended} instrumentation.
+	 *
+	 * @throws Exception Indicates an issue either access files or applying the transformations.
+	 */
+	protected void processJarFile(final File file, final Set classNames) throws Exception {
+        File tempFile = File.createTempFile(
+		        file.getName(),
+		        null,
+		        new File( file.getAbsoluteFile().getParent() )
+        );
+
+        try {
+			FileOutputStream fout = new FileOutputStream( tempFile, false );
+			try {
+				final ZipOutputStream out = new ZipOutputStream( fout );
+				ZipEntryHandler transformer = new ZipEntryHandler() {
+					public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
+								logger.debug( "starting zip entry : " + entry.toString() );
+								if ( !entry.isDirectory() ) {
+									// see if the entry represents a class file
+									DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
+									if ( din.readInt() == CLASS_MAGIC ) {
+										ClassDescriptor descriptor = getClassDescriptor( byteCode );
+										ClassTransformer transformer = getClassTransformer( descriptor, classNames );
+										if ( transformer == null ) {
+											logger.debug( "no transformer for zip entry :  " + entry.toString() );
+										}
+										else {
+											logger.info( "processing class : " + descriptor.getName() + ";  entry = " + file.getAbsolutePath() );
+											byteCode = transformer.transform(
+													getClass().getClassLoader(),
+													descriptor.getName(),
+													null,
+													null,
+													descriptor.getBytes()
+											);
+										}
+									}
+									else {
+										logger.debug( "ignoring zip entry : " + entry.toString() );
+									}
+								}
+
+								ZipEntry outEntry = new ZipEntry( entry.getName() );
+								outEntry.setMethod( entry.getMethod() );
+								outEntry.setComment( entry.getComment() );
+								outEntry.setSize( byteCode.length );
+
+								if ( outEntry.getMethod() == ZipEntry.STORED ){
+									CRC32 crc = new CRC32();
+									crc.update( byteCode );
+									outEntry.setCrc( crc.getValue() );
+									outEntry.setCompressedSize( byteCode.length );
+								}
+								out.putNextEntry( outEntry );
+								out.write( byteCode );
+								out.closeEntry();
+					}
+				};
+				ZipFileProcessor processor = new ZipFileProcessor( transformer );
+				processor.process( file );
+				out.close();
+			}
+			finally{
+				fout.close();
+			}
+
+            if ( file.delete() ) {
+	            File newFile = new File( tempFile.getAbsolutePath() );
+                if( !newFile.renameTo( file ) ) {
+	                throw new IOException( "can not rename " + tempFile + " to " + file );
+                }
+            }
+            else {
+	            throw new IOException( "can not delete " + file );
+            }
+        }
+        finally {
+	        if ( ! tempFile.delete() ) {
+				logger.info( "Unable to cleanup temporary jar file : " + tempFile.getAbsolutePath() );
+			}
+        }
+	}
+
+	/**
+	 * Allows control over what exacctly to transform.
+	 */
+	protected class CustomFieldFilter implements FieldFilter {
+		private final ClassDescriptor descriptor;
+		private final Set classNames;
+
+		public CustomFieldFilter(ClassDescriptor descriptor, Set classNames) {
+			this.descriptor = descriptor;
+			this.classNames = classNames;
+		}
+
+		public boolean shouldInstrumentField(String className, String fieldName) {
+			if ( descriptor.getName().equals( className ) ) {
+				logger.trace( "accepting transformation of field [" + className + "." + fieldName + "]" );
+				return true;
+			}
+			else {
+				logger.trace( "rejecting transformation of field [" + className + "." + fieldName + "]" );
+				return false;
+			}
+		}
+
+		public boolean shouldTransformFieldAccess(
+				String transformingClassName,
+				String fieldOwnerClassName,
+				String fieldName) {
+			if ( descriptor.getName().equals( fieldOwnerClassName ) ) {
+				logger.trace( "accepting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" );
+				return true;
+			}
+			else if ( options.performExtendedInstrumentation() && classNames.contains( fieldOwnerClassName ) ) {
+				logger.trace( "accepting extended transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" );
+				return true;
+			}
+			else {
+				logger.trace( "rejecting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]; caller = " + transformingClassName  );
+				return false;
+			}
+		}
+	}
+
+	/**
+	 * General strategy contract for handling entries in an archive file.
+	 */
+	private static interface ZipEntryHandler {
+		/**
+		 * Apply strategy to the given archive entry.
+		 *
+		 * @param entry The archive file entry.
+		 * @param byteCode
+		 *
+		 * @throws Exception
+		 */
+		public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception;
+	}
+
+	/**
+	 * Applies {@link ZipEntryHandler} strategies to the entries of an archive file.
+	 */
+	private static class ZipFileProcessor {
+		private final ZipEntryHandler entryHandler;
+
+		public ZipFileProcessor(ZipEntryHandler entryHandler) {
+			this.entryHandler = entryHandler;
+		}
+
+		public void process(File file) throws Exception {
+			ZipInputStream zip = new ZipInputStream( new FileInputStream( file ) );
+
+			try {
+				ZipEntry entry;
+				while ( (entry = zip.getNextEntry()) != null ) {
+					byte bytes[] = ByteCodeHelper.readByteCode( zip );
+					entryHandler.handleEntry( entry, bytes );
+					zip.closeEntry();
+				}
+            }
+            finally {
+	            zip.close();
+            }
+		}
+	}
+}

Added: core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/CGLIBInstrumenter.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/CGLIBInstrumenter.java	                        (rev 0)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/CGLIBInstrumenter.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -0,0 +1,100 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.bytecode.buildtime;
+
+import java.util.Set;
+import java.io.ByteArrayInputStream;
+
+import org.hibernate.bytecode.util.ClassDescriptor;
+import org.hibernate.bytecode.util.BasicClassFilter;
+import org.hibernate.bytecode.ClassTransformer;
+import org.hibernate.bytecode.cglib.BytecodeProviderImpl;
+import org.hibernate.repackage.cglib.asm.ClassReader;
+import org.hibernate.repackage.cglib.core.ClassNameReader;
+import org.hibernate.repackage.cglib.transform.impl.InterceptFieldEnabled;
+
+/**
+ * Strategy for performing build-time instrumentation of persistent classes in order to enable
+ * field-level interception using CGLIB.
+ *
+ * @author Steve Ebersole
+ * @author Gavin King
+ */
+public class CGLIBInstrumenter extends AbstractInstrumenter {
+	private static final BasicClassFilter CLASS_FILTER = new BasicClassFilter();
+
+	private final BytecodeProviderImpl provider = new BytecodeProviderImpl();
+
+	public CGLIBInstrumenter(Logger logger, Options options) {
+		super( logger, options );
+	}
+
+	protected ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception {
+		return new CustomClassDescriptor( byecode );
+	}
+
+	protected ClassTransformer getClassTransformer(ClassDescriptor descriptor, Set classNames) {
+		if ( descriptor.isInstrumented() ) {
+			logger.debug( "class [" + descriptor.getName() + "] already instrumented" );
+			return null;
+		}
+		else {
+			return provider.getTransformer( CLASS_FILTER, new CustomFieldFilter( descriptor, classNames ) );
+		}
+	}
+
+	private static class CustomClassDescriptor implements ClassDescriptor {
+		private final byte[] bytecode;
+		private final String name;
+		private final boolean isInstrumented;
+
+		public CustomClassDescriptor(byte[] bytecode) throws Exception {
+			this.bytecode = bytecode;
+			ClassReader reader = new ClassReader( new ByteArrayInputStream( bytecode ) );
+			String[] names = ClassNameReader.getClassInfo( reader );
+			this.name = names[0];
+			boolean instrumented = false;
+			for ( int i = 1; i < names.length; i++ ) {
+				if ( InterceptFieldEnabled.class.getName().equals( names[i] ) ) {
+					instrumented = true;
+					break;
+				}
+			}
+			this.isInstrumented = instrumented;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public boolean isInstrumented() {
+			return isInstrumented;
+		}
+
+		public byte[] getBytes() {
+			return bytecode;
+		}
+	}
+
+}

Added: core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/ExecutionException.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/ExecutionException.java	                        (rev 0)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/ExecutionException.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -0,0 +1,43 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.bytecode.buildtime;
+
+/**
+ * Indicates problem performing the instrumentation execution.
+ *
+ * @author Steve Ebersole
+ */
+public class ExecutionException extends RuntimeException {
+	public ExecutionException(String message) {
+		super( message );
+	}
+
+	public ExecutionException(Throwable cause) {
+		super( cause );
+	}
+
+	public ExecutionException(String message, Throwable cause) {
+		super( message, cause );
+	}
+}

Added: core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/Instrumenter.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/Instrumenter.java	                        (rev 0)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/Instrumenter.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -0,0 +1,39 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.bytecode.buildtime;
+
+import java.util.Set;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public interface Instrumenter {
+	public void execute(Set files);
+
+	public static interface Options {
+		public boolean performExtendedInstrumentation();
+	}
+}

Added: core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/JavassistInstrumenter.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/JavassistInstrumenter.java	                        (rev 0)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/JavassistInstrumenter.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -0,0 +1,98 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.bytecode.buildtime;
+
+import java.util.Set;
+import java.io.IOException;
+import java.io.DataInputStream;
+import java.io.ByteArrayInputStream;
+
+import javassist.bytecode.ClassFile;
+
+import org.hibernate.bytecode.util.ClassDescriptor;
+import org.hibernate.bytecode.util.BasicClassFilter;
+import org.hibernate.bytecode.ClassTransformer;
+import org.hibernate.bytecode.javassist.BytecodeProviderImpl;
+import org.hibernate.bytecode.javassist.FieldHandled;
+
+/**
+ * Strategy for performing build-time instrumentation of persistent classes in order to enable
+ * field-level interception using Javassist.
+ *
+ * @author Steve Ebersole
+ * @author Muga Nishizawa
+ */
+public class JavassistInstrumenter extends AbstractInstrumenter {
+
+	private static final BasicClassFilter CLASS_FILTER = new BasicClassFilter();
+
+	private final BytecodeProviderImpl provider = new BytecodeProviderImpl();
+
+	public JavassistInstrumenter(Logger logger, Options options) {
+		super( logger, options );
+	}
+
+	protected ClassDescriptor getClassDescriptor(byte[] bytecode) throws IOException {
+		return new CustomClassDescriptor( bytecode );
+	}
+
+	protected ClassTransformer getClassTransformer(ClassDescriptor descriptor, Set classNames) {
+		if ( descriptor.isInstrumented() ) {
+			logger.debug( "class [" + descriptor.getName() + "] already instrumented" );
+			return null;
+		}
+		else {
+			return provider.getTransformer( CLASS_FILTER, new CustomFieldFilter( descriptor, classNames ) );
+		}
+	}
+
+	private static class CustomClassDescriptor implements ClassDescriptor {
+		private final byte[] bytes;
+		private final ClassFile classFile;
+
+		public CustomClassDescriptor(byte[] bytes) throws IOException {
+			this.bytes = bytes;
+			this.classFile = new ClassFile( new DataInputStream( new ByteArrayInputStream( bytes ) ) );
+		}
+
+		public String getName() {
+			return classFile.getName();
+		}
+
+		public boolean isInstrumented() {
+			String[] intfs = classFile.getInterfaces();
+			for ( int i = 0; i < intfs.length; i++ ) {
+				if ( FieldHandled.class.getName().equals( intfs[i] ) ) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		public byte[] getBytes() {
+			return bytes;
+		}
+	}
+
+}

Added: core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/Logger.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/Logger.java	                        (rev 0)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/bytecode/buildtime/Logger.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -0,0 +1,42 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.bytecode.buildtime;
+
+/**
+ * Provides an abstraction for how instrumentation does logging because it is usually run in environments (Ant/Maven)
+ * with their own logging infrastructure.  This abstraction allows proper bridging.
+ *
+ * @author Steve Ebersole
+ */
+public interface Logger {
+	public void trace(String message);
+
+	public void debug(String message);
+
+	public void info(String message);
+
+	public void warn(String message);
+
+	public void error(String message);
+}

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/BasicInstrumentationTask.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/BasicInstrumentationTask.java	2009-03-04 02:19:29 UTC (rev 16067)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/BasicInstrumentationTask.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -20,7 +20,6 @@
  * Free Software Foundation, Inc.
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
- *
  */
 package org.hibernate.tool.instrument;
 
@@ -29,43 +28,31 @@
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.DirectoryScanner;
 import org.apache.tools.ant.types.FileSet;
-import org.hibernate.bytecode.util.ClassDescriptor;
-import org.hibernate.bytecode.util.ByteCodeHelper;
-import org.hibernate.bytecode.util.FieldFilter;
-import org.hibernate.bytecode.ClassTransformer;
 
+import org.hibernate.bytecode.buildtime.Instrumenter;
+import org.hibernate.bytecode.buildtime.Logger;
+
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Set;
 import java.util.HashSet;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
-import java.util.zip.ZipEntry;
-import java.util.zip.CRC32;
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.io.IOException;
-import java.io.FileInputStream;
-import java.io.DataInputStream;
-import java.io.ByteArrayInputStream;
 
 /**
- * Super class for all Hibernate instrumentation tasks.  Provides the basic
- * templating of how instrumentation should occur.
+ * Super class for all Hibernate instrumentation tasks.  Provides the basic templating of how instrumentation
+ * should occur; subclasses simply plug in to that process appropriately for the given bytecode provider.
  *
  * @author Steve Ebersole
  */
-public abstract class BasicInstrumentationTask extends Task {
+public abstract class BasicInstrumentationTask extends Task implements Instrumenter.Options {
 
-	private static final int ZIP_MAGIC = 0x504B0304;
-	private static final int CLASS_MAGIC = 0xCAFEBABE;
+	private final LoggerBridge logger = new LoggerBridge();
 
-	protected final Logger logger = new Logger();
 	private List filesets = new ArrayList();
-	private Set classNames = new HashSet();
 	private boolean extended;
+
+	// deprecated option...
 	private boolean verbose;
 
 	public void addFileset(FileSet set) {
@@ -92,32 +79,24 @@
 		this.verbose = verbose;
 	}
 
+	public final boolean performExtendedInstrumentation() {
+		return isExtended();
+	}
+
+	protected abstract Instrumenter buildInstrumenter(Logger logger, Instrumenter.Options options);
+
 	public void execute() throws BuildException {
-		if ( isExtended() ) {
-			collectClassNames();
+		try {
+			buildInstrumenter( logger, this )
+					.execute( collectSpecifiedFiles() );
 		}
-		logger.info( "starting instrumentation" );
-		Project project = getProject();
-		Iterator filesets = filesets();
-		while ( filesets.hasNext() ) {
-			FileSet fs = ( FileSet ) filesets.next();
-			DirectoryScanner ds = fs.getDirectoryScanner( project );
-			String[] includedFiles = ds.getIncludedFiles();
-			File d = fs.getDir( project );
-			for ( int i = 0; i < includedFiles.length; ++i ) {
-				File file = new File( d, includedFiles[i] );
-				try {
-					processFile( file );
-				}
-				catch ( Exception e ) {
-					throw new BuildException( e );
-				}
-			}
+		catch ( Throwable t ) {
+			throw new BuildException( t );
 		}
 	}
 
-	private void collectClassNames() {
-		logger.info( "collecting class names for extended instrumentation determination" );
+	private Set collectSpecifiedFiles() {
+		HashSet files = new HashSet();
 		Project project = getProject();
 		Iterator filesets = filesets();
 		while ( filesets.hasNext() ) {
@@ -126,239 +105,14 @@
 			String[] includedFiles = ds.getIncludedFiles();
 			File d = fs.getDir( project );
 			for ( int i = 0; i < includedFiles.length; ++i ) {
-				File file = new File( d, includedFiles[i] );
-				try {
-					collectClassNames( file );
-				}
-				catch ( Exception e ) {
-					throw new BuildException( e );
-				}
+				files.add( new File( d, includedFiles[i] ) );
 			}
 		}
-		logger.info( classNames.size() + " class(es) being checked" );
+		return files;
 	}
 
-	private void collectClassNames(File file) throws Exception {
-	    if ( isClassFile( file ) ) {
-			byte[] bytes = ByteCodeHelper.readByteCode( file );
-			ClassDescriptor descriptor = getClassDescriptor( bytes );
-		    classNames.add( descriptor.getName() );
-	    }
-	    else if ( isJarFile( file ) ) {
-		    ZipEntryHandler collector = new ZipEntryHandler() {
-			    public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
-					if ( !entry.isDirectory() ) {
-						// see if the entry represents a class file
-						DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
-						if ( din.readInt() == CLASS_MAGIC ) {
-				            classNames.add( getClassDescriptor( byteCode ).getName() );
-						}
-					}
-			    }
-		    };
-		    ZipFileProcessor processor = new ZipFileProcessor( collector );
-		    processor.process( file );
-	    }
-	}
-
-	protected void processFile(File file) throws Exception {
-		logger.verbose( "processing file : " + file.toURL() );
-	    if ( isClassFile( file ) ) {
-	        processClassFile(file);
-	    }
-	    else if ( isJarFile( file ) ) {
-	        processJarFile(file);
-	    }
-	    else {
-		    logger.verbose( "ignoring " + file.toURL() );
-
-	    }
-	}
-
-	protected final boolean isClassFile(File file) throws IOException {
-        return checkMagic( file, CLASS_MAGIC );
-    }
-
-    protected final boolean isJarFile(File file) throws IOException {
-        return checkMagic(file, ZIP_MAGIC);
-    }
-
-	protected final boolean checkMagic(File file, long magic) throws IOException {
-        DataInputStream in = new DataInputStream( new FileInputStream( file ) );
-        try {
-            int m = in.readInt();
-            return magic == m;
-        }
-        finally {
-            in.close();
-        }
-    }
-
-	protected void processClassFile(File file) throws Exception {
-		logger.verbose( "Starting class file : " + file.toURL() );
-		byte[] bytes = ByteCodeHelper.readByteCode( file );
-		ClassDescriptor descriptor = getClassDescriptor( bytes );
-		ClassTransformer transformer = getClassTransformer( descriptor );
-		if ( transformer == null ) {
-			logger.verbose( "skipping file : " + file.toURL() );
-			return;
-		}
-
-		logger.info( "processing class [" + descriptor.getName() + "]; file = " + file.toURL() );
-		byte[] transformedBytes = transformer.transform(
-				getClass().getClassLoader(),
-				descriptor.getName(),
-				null,
-				null,
-				descriptor.getBytes()
-		);
-
-		OutputStream out = new FileOutputStream( file );
-		try {
-			out.write( transformedBytes );
-			out.flush();
-		}
-		finally {
-			try {
-				out.close();
-			}
-			catch ( IOException ignore) {
-				// intentionally empty
-			}
-		}
-	}
-
-	protected void processJarFile(final File file) throws Exception {
-		logger.verbose( "starting jar file : " + file.toURL() );
-
-        File tempFile = File.createTempFile(
-		        file.getName(),
-		        null,
-		        new File( file.getAbsoluteFile().getParent() )
-        );
-
-        try {
-			FileOutputStream fout = new FileOutputStream( tempFile, false );
-			try {
-				final ZipOutputStream out = new ZipOutputStream( fout );
-				ZipEntryHandler transformer = new ZipEntryHandler() {
-					public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception {
-								logger.verbose( "starting entry : " + entry.toString() );
-								if ( !entry.isDirectory() ) {
-									// see if the entry represents a class file
-									DataInputStream din = new DataInputStream( new ByteArrayInputStream( byteCode ) );
-									if ( din.readInt() == CLASS_MAGIC ) {
-										ClassDescriptor descriptor = getClassDescriptor( byteCode );
-										ClassTransformer transformer = getClassTransformer( descriptor );
-										if ( transformer == null ) {
-											logger.verbose( "skipping entry : " + entry.toString() );
-										}
-										else {
-											logger.info( "processing class [" + descriptor.getName() + "]; entry = " + file.toURL() );
-											byteCode = transformer.transform(
-													getClass().getClassLoader(),
-													descriptor.getName(),
-													null,
-													null,
-													descriptor.getBytes()
-											);
-										}
-									}
-									else {
-										logger.verbose( "ignoring zip entry : " + entry.toString() );
-									}
-								}
-
-								ZipEntry outEntry = new ZipEntry( entry.getName() );
-								outEntry.setMethod( entry.getMethod() );
-								outEntry.setComment( entry.getComment() );
-								outEntry.setSize( byteCode.length );
-
-								if ( outEntry.getMethod() == ZipEntry.STORED ){
-									CRC32 crc = new CRC32();
-									crc.update( byteCode );
-									outEntry.setCrc( crc.getValue() );
-									outEntry.setCompressedSize( byteCode.length );
-								}
-								out.putNextEntry( outEntry );
-								out.write( byteCode );
-								out.closeEntry();
-					}
-				};
-				ZipFileProcessor processor = new ZipFileProcessor( transformer );
-				processor.process( file );
-				out.close();
-			}
-			finally{
-				fout.close();
-			}
-
-            if ( file.delete() ) {
-	            File newFile = new File( tempFile.getAbsolutePath() );
-                if( !newFile.renameTo( file ) ) {
-	                throw new IOException( "can not rename " + tempFile + " to " + file );
-                }
-            }
-            else {
-	            throw new IOException("can not delete " + file);
-            }
-        }
-        finally {
-	        tempFile.delete();
-        }
-	}
-
-	protected boolean isBeingIntrumented(String className) {
-		logger.verbose( "checking to see if class [" + className + "] is set to be instrumented" );
-		return classNames.contains( className );
-	}
-
-	protected abstract ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception;
-
-	protected abstract ClassTransformer getClassTransformer(ClassDescriptor descriptor);
-
-	protected class CustomFieldFilter implements FieldFilter {
-		private final ClassDescriptor descriptor;
-
-		public CustomFieldFilter(ClassDescriptor descriptor) {
-			this.descriptor = descriptor;
-		}
-
-		public boolean shouldInstrumentField(String className, String fieldName) {
-			if ( descriptor.getName().equals( className ) ) {
-				logger.verbose( "accepting transformation of field [" + className + "." + fieldName + "]" );
-				return true;
-			}
-			else {
-				logger.verbose( "rejecting transformation of field [" + className + "." + fieldName + "]" );
-				return false;
-			}
-		}
-
-		public boolean shouldTransformFieldAccess(
-				String transformingClassName,
-				String fieldOwnerClassName,
-				String fieldName) {
-			if ( descriptor.getName().equals( fieldOwnerClassName ) ) {
-				logger.verbose( "accepting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" );
-				return true;
-			}
-			else if ( isExtended() && isBeingIntrumented( fieldOwnerClassName ) ) {
-				logger.verbose( "accepting extended transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]" );
-				return true;
-			}
-			else {
-				logger.verbose( "rejecting transformation of field access [" + fieldOwnerClassName + "." + fieldName + "]; caller = " + transformingClassName  );
-				return false;
-			}
-		}
-	}
-
-	protected class Logger {
-		public void verbose(String message) {
-			if ( verbose ) {
-				System.out.println( message );
-			}
+	protected class LoggerBridge implements Logger {
+		public void trace(String message) {
 			log( message, Project.MSG_VERBOSE );
 		}
 
@@ -373,34 +127,10 @@
 		public void warn(String message) {
 			log( message, Project.MSG_WARN );
 		}
-	}
 
-
-	private static interface ZipEntryHandler {
-		public void handleEntry(ZipEntry entry, byte[] byteCode) throws Exception;
-	}
-
-	private static class ZipFileProcessor {
-		private final ZipEntryHandler entryHandler;
-
-		public ZipFileProcessor(ZipEntryHandler entryHandler) {
-			this.entryHandler = entryHandler;
+		public void error(String message) {
+			log( message, Project.MSG_ERR );
 		}
-
-		public void process(File file) throws Exception {
-			ZipInputStream zip = new ZipInputStream( new FileInputStream( file ) );
-
-			try {
-				ZipEntry entry;
-				while ( (entry = zip.getNextEntry()) != null ) {
-					byte bytes[] = ByteCodeHelper.readByteCode( zip );
-					entryHandler.handleEntry( entry, bytes );
-					zip.closeEntry();
-				}
-            }
-            finally {
-	            zip.close();
-            }
-		}
 	}
+
 }

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/cglib/InstrumentTask.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/cglib/InstrumentTask.java	2009-03-04 02:19:29 UTC (rev 16067)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/cglib/InstrumentTask.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -24,18 +24,11 @@
  */
 package org.hibernate.tool.instrument.cglib;
 
-import org.hibernate.bytecode.util.BasicClassFilter;
-import org.hibernate.bytecode.util.ClassDescriptor;
-import org.hibernate.bytecode.cglib.BytecodeProviderImpl;
-import org.hibernate.bytecode.ClassTransformer;
+import org.hibernate.bytecode.buildtime.CGLIBInstrumenter;
+import org.hibernate.bytecode.buildtime.Instrumenter;
+import org.hibernate.bytecode.buildtime.Logger;
 import org.hibernate.tool.instrument.BasicInstrumentationTask;
-import org.hibernate.repackage.cglib.asm.ClassReader;
 
-import java.io.ByteArrayInputStream;
-
-import org.hibernate.repackage.cglib.core.ClassNameReader;
-import org.hibernate.repackage.cglib.transform.impl.InterceptFieldEnabled;
-
 /**
  * An Ant task for instrumenting persistent classes in order to enable
  * field-level interception using CGLIB.
@@ -50,7 +43,7 @@
  * required Hibernate and CGLIB libraries.
  * <p/>
  * And then use it like:<pre>
- * <instrument verbose="true">
+ * <instrument>
  *     <fileset dir="${testclasses.dir}/org/hibernate/test">
  *         <include name="yadda/yadda/**"/>
  *         ...
@@ -62,7 +55,7 @@
  * <p/>
  * Optionally you can chose to enable "Extended Instrumentation" if desired
  * by specifying the extended attriubute on the task:<pre>
- * <instrument verbose="true" extended="true">
+ * <instrument extended="true">
  *     ...
  * </instrument>
  * </pre>
@@ -72,58 +65,7 @@
  * @author Steve Ebersole
  */
 public class InstrumentTask extends BasicInstrumentationTask {
-
-	private static final BasicClassFilter CLASS_FILTER = new BasicClassFilter();
-
-	private final BytecodeProviderImpl provider = new BytecodeProviderImpl();
-
-
-	protected ClassDescriptor getClassDescriptor(byte[] byecode) throws Exception {
-		return new CustomClassDescriptor( byecode );
+	protected Instrumenter buildInstrumenter(Logger logger, Instrumenter.Options options) {
+		return new CGLIBInstrumenter( logger, options );
 	}
-
-	protected ClassTransformer getClassTransformer(ClassDescriptor descriptor) {
-		if ( descriptor.isInstrumented() ) {
-			logger.verbose( "class [" + descriptor.getName() + "] already instrumented" );
-			return null;
-		}
-		else {
-			return provider.getTransformer( CLASS_FILTER, new CustomFieldFilter( descriptor ) );
-		}
-	}
-
-	private static class CustomClassDescriptor implements ClassDescriptor {
-		private final byte[] bytecode;
-		private final String name;
-		private final boolean isInstrumented;
-
-		public CustomClassDescriptor(byte[] bytecode) throws Exception {
-			this.bytecode = bytecode;
-			ClassReader reader = new ClassReader( new ByteArrayInputStream( bytecode ) );
-			String[] names = ClassNameReader.getClassInfo( reader );
-			this.name = names[0];
-			boolean instrumented = false;
-			for ( int i = 1; i < names.length; i++ ) {
-				if ( InterceptFieldEnabled.class.getName().equals( names[i] ) ) {
-					instrumented = true;
-					break;
-				}
-			}
-			this.isInstrumented = instrumented;
-		}
-
-		public String getName() {
-			return name;
-		}
-
-		public boolean isInstrumented() {
-			return isInstrumented;
-		}
-
-		public byte[] getBytes() {
-			return bytecode;
-		}
-	}
-
-
 }

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java	2009-03-04 02:19:29 UTC (rev 16067)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -24,18 +24,10 @@
  */
 package org.hibernate.tool.instrument.javassist;
 
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.ByteArrayInputStream;
-
-import javassist.bytecode.ClassFile;
-
+import org.hibernate.bytecode.buildtime.Instrumenter;
+import org.hibernate.bytecode.buildtime.JavassistInstrumenter;
+import org.hibernate.bytecode.buildtime.Logger;
 import org.hibernate.tool.instrument.BasicInstrumentationTask;
-import org.hibernate.bytecode.util.ClassDescriptor;
-import org.hibernate.bytecode.util.BasicClassFilter;
-import org.hibernate.bytecode.ClassTransformer;
-import org.hibernate.bytecode.javassist.BytecodeProviderImpl;
-import org.hibernate.bytecode.javassist.FieldHandled;
 
 /**
  * An Ant task for instrumenting persistent classes in order to enable
@@ -73,51 +65,7 @@
  * @author Steve Ebersole
  */
 public class InstrumentTask extends BasicInstrumentationTask {
-
-	private static final BasicClassFilter CLASS_FILTER = new BasicClassFilter();
-
-	private final BytecodeProviderImpl provider = new BytecodeProviderImpl();
-
-	protected ClassDescriptor getClassDescriptor(byte[] bytecode) throws IOException {
-		return new CustomClassDescriptor( bytecode );
+	protected Instrumenter buildInstrumenter(Logger logger, Instrumenter.Options options) {
+		return new JavassistInstrumenter( logger, options );
 	}
-
-	protected ClassTransformer getClassTransformer(ClassDescriptor descriptor) {
-		if ( descriptor.isInstrumented() ) {
-			logger.verbose( "class [" + descriptor.getName() + "] already instrumented" );
-			return null;
-		}
-		else {
-			return provider.getTransformer( CLASS_FILTER, new CustomFieldFilter( descriptor ) );
-		}
-	}
-
-	private static class CustomClassDescriptor implements ClassDescriptor {
-		private final byte[] bytes;
-		private final ClassFile classFile;
-
-		public CustomClassDescriptor(byte[] bytes) throws IOException {
-			this.bytes = bytes;
-			this.classFile = new ClassFile( new DataInputStream( new ByteArrayInputStream( bytes ) ) );
-		}
-
-		public String getName() {
-			return classFile.getName();
-		}
-
-		public boolean isInstrumented() {
-			String[] intfs = classFile.getInterfaces();
-			for ( int i = 0; i < intfs.length; i++ ) {
-				if ( FieldHandled.class.getName().equals( intfs[i] ) ) {
-					return true;
-				}
-			}
-			return false;
-		}
-
-		public byte[] getBytes() {
-			return bytes;
-		}
-	}
-
 }


Property changes on: core/branches/Branch_3_3/hibernate-maven-plugin
___________________________________________________________________
Name: svn:ignore
   + target
local
*.ipr
*.iws
*.iml
.classpath
.project
.nbattrs
*.log
*.properties
.clover


Added: core/branches/Branch_3_3/hibernate-maven-plugin/pom.xml
===================================================================
--- core/branches/Branch_3_3/hibernate-maven-plugin/pom.xml	                        (rev 0)
+++ core/branches/Branch_3_3/hibernate-maven-plugin/pom.xml	2009-03-04 02:20:50 UTC (rev 16068)
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Hibernate, Relational Persistence for Idiomatic Java
+  ~
+  ~ Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+  ~ indicated by the @author tags or express copyright attribution
+  ~ statements applied by the authors.  All third-party contributions are
+  ~ distributed under license by Red Hat Middleware LLC.
+  ~
+  ~ This copyrighted material is made available to anyone wishing to use, modify,
+  ~ copy, or redistribute it subject to the terms and conditions of the GNU
+  ~ Lesser General Public License, as published by the Free Software Foundation.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+  ~ for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public License
+  ~ along with this distribution; if not, write to:
+  ~ Free Software Foundation, Inc.
+  ~ 51 Franklin Street, Fifth Floor
+  ~ Boston, MA  02110-1301  USA
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>hibernate-parent</artifactId>
+        <groupId>org.hibernate</groupId>
+        <version>3.3.2-SNAPSHOT</version>
+        <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.hibernate</groupId>
+    <artifactId>hibernate-maven-plugin</artifactId>
+    <packaging>mojo</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>${groupId}</groupId>
+            <artifactId>hibernate-core</artifactId>
+            <version>${version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>2.0.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-project</artifactId>
+            <version>2.0.9</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

Added: core/branches/Branch_3_3/hibernate-maven-plugin/src/main/java/org/hibernate/maven/InstrumentationMojo.java
===================================================================
--- core/branches/Branch_3_3/hibernate-maven-plugin/src/main/java/org/hibernate/maven/InstrumentationMojo.java	                        (rev 0)
+++ core/branches/Branch_3_3/hibernate-maven-plugin/src/main/java/org/hibernate/maven/InstrumentationMojo.java	2009-03-04 02:20:50 UTC (rev 16068)
@@ -0,0 +1,175 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.maven;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.io.File;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.artifact.Artifact;
+import org.codehaus.plexus.util.DirectoryScanner;
+
+import org.hibernate.bytecode.buildtime.Instrumenter;
+import org.hibernate.bytecode.buildtime.Logger;
+import org.hibernate.bytecode.buildtime.JavassistInstrumenter;
+import org.hibernate.bytecode.buildtime.CGLIBInstrumenter;
+
+/**
+ * @goal instrument
+ * @phase process-classes
+ * @requiresDependencyResolution
+ *
+ * @author Steve Ebersole
+ */
+public class InstrumentationMojo extends AbstractMojo implements Instrumenter.Options {
+	/**
+     * INTERNAL : The Maven Project to which we are attached
+     *
+     * @parameter expression="${project}"
+     * @required
+     */
+    private MavenProject project;
+
+	/**
+	 * Specifies the directory containing the classes to be instrumented.  By default we use the
+	 * project's output directory, which in turn defaults to <samp>${basedir}/target/classes</samp>.
+	 *
+	 * @parameter expression="${project.build.outputDirectory}"
+	 * @required
+	 */
+	private File instrumentationDirectory;
+
+	/**
+	 * @parameter
+	 */
+	private boolean extended;
+
+	/**
+	 * @parameter
+	 */
+	private String provider;
+
+	public boolean performExtendedInstrumentation() {
+		return extended;
+	}
+
+	public void execute() throws MojoExecutionException, MojoFailureException {
+		// first, lets determine whether to apply cglib or javassist based instrumentation...
+		if ( provider == null ) {
+			provider = determineProvider();
+			if ( provider == null ) {
+				throw new MojoExecutionException( "Unable to determine provider to use" );
+			}
+		}
+
+		Instrumenter instrumenter = resolveInstrumenter( provider, new LoggingBridge() );
+		try {
+			instrumenter.execute( collectFilesToProcess() );
+		}
+		catch (  Throwable t ) {
+			throw new MojoExecutionException( "Error executing instrumentation", t );
+		}
+	}
+
+	private Set collectFilesToProcess() {
+		DirectoryScanner scanner = new DirectoryScanner();
+		scanner.setBasedir( instrumentationDirectory );
+		scanner.setIncludes( new String[] { "**/*.class" } );
+		scanner.addDefaultExcludes();
+		scanner.scan();
+		String[] includedFiles = scanner.getIncludedFiles();
+		HashSet fileSet = new HashSet( includedFiles.length + (int)(.75*includedFiles.length) + 1 );
+		fileSet.addAll( Arrays.asList( includedFiles ) );
+		return fileSet;
+	}
+
+	private Instrumenter resolveInstrumenter(String provider, Logger logger) throws MojoExecutionException {
+		if ( "javassist".equals( provider ) ) {
+			return new JavassistInstrumenter( logger, this );
+		}
+		else if ( "cglib".equals( provider ) ) {
+			return new CGLIBInstrumenter( logger, this );
+		}
+		else {
+			throw new MojoExecutionException( "Unable to resolve provider [" + provider + "] to appropriate instrumenter" );
+		}
+	}
+
+	/**
+	 * Determine the provider to use.  Called in the cases where the user did not explicitly specify; so we look
+	 * through the dependencies for the project and decide which provider should be applied.
+	 * <p/>
+	 * NOTE: this impl prefers javassist.
+	 *
+	 * @return The provider determined from project's dependencies.
+	 */
+	private String determineProvider() {
+		if ( project.getCompileArtifacts() != null ) {
+			boolean foundCglib = false;
+			Iterator itr = project.getCompileArtifacts().iterator();
+			while ( itr.hasNext() ) {
+				final Artifact artifact = ( Artifact ) itr.next();
+				if ( "javassist".equals( artifact.getGroupId() ) && "javassist".equals( artifact.getArtifactId() ) ) {
+					return "javassist";
+				}
+				else if ( "org.hibernate".equals( artifact.getGroupId() )
+						&& "hibernate-cglib-repack".equals( artifact.getArtifactId() ) ) {
+					foundCglib = true;
+				}
+			}
+			if ( foundCglib ) {
+				return "cglib";
+			}
+		}
+		return null;
+	}
+
+	private class LoggingBridge implements Logger {
+		public void trace(String message) {
+			getLog().debug( message );
+		}
+
+		public void debug(String message) {
+			getLog().debug( message );
+		}
+
+		public void info(String message) {
+			getLog().info( message );
+		}
+
+		public void warn(String message) {
+			getLog().warn( message );
+		}
+
+		public void error(String message) {
+			getLog().error( message );
+		}
+	}
+}

Modified: core/branches/Branch_3_3/pom.xml
===================================================================
--- core/branches/Branch_3_3/pom.xml	2009-03-04 02:19:29 UTC (rev 16067)
+++ core/branches/Branch_3_3/pom.xml	2009-03-04 02:20:50 UTC (rev 16068)
@@ -57,7 +57,8 @@
         <module>testing</module>
         <module>testsuite</module>
         <module>tutorials</module>
-<!--
+        <module>hibernate-maven-plugin</module>
+        <!--
     Need to scope bytecode providers first...
         <module>bytecode-cglib</module>
         <module>bytecode-javassist</module>




More information about the hibernate-commits mailing list