001: //$Id: $
002: package org.hibernate.bytecode.cglib;
003:
004: import java.security.ProtectionDomain;
005: import java.io.ByteArrayInputStream;
006: import java.io.IOException;
007: import java.io.ByteArrayOutputStream;
008:
009: import net.sf.cglib.transform.ClassTransformer;
010: import net.sf.cglib.transform.TransformingClassGenerator;
011: import net.sf.cglib.transform.ClassReaderGenerator;
012: import net.sf.cglib.transform.impl.InterceptFieldEnabled;
013: import net.sf.cglib.transform.impl.InterceptFieldFilter;
014: import net.sf.cglib.transform.impl.InterceptFieldTransformer;
015: import net.sf.cglib.core.ClassNameReader;
016: import net.sf.cglib.core.DebuggingClassWriter;
017: import org.apache.commons.logging.Log;
018: import org.apache.commons.logging.LogFactory;
019: import org.hibernate.bytecode.AbstractClassTransformerImpl;
020: import org.hibernate.bytecode.util.FieldFilter;
021: import org.hibernate.bytecode.util.ClassFilter;
022: import org.hibernate.HibernateException;
023: import org.objectweb.asm.Attribute;
024: import org.objectweb.asm.Type;
025: import org.objectweb.asm.ClassReader;
026: import org.objectweb.asm.ClassWriter;
027: import org.objectweb.asm.attrs.Attributes;
028:
029: /**
030: * Enhance the classes allowing them to implements InterceptFieldEnabled
031: * This interface is then used by Hibernate for some optimizations.
032: *
033: * @author Emmanuel Bernard
034: * @author Steve Ebersole
035: */
036: public class CglibClassTransformer extends AbstractClassTransformerImpl {
037:
038: private static Log log = LogFactory
039: .getLog(CglibClassTransformer.class.getName());
040:
041: public CglibClassTransformer(ClassFilter classFilter,
042: FieldFilter fieldFilter) {
043: super (classFilter, fieldFilter);
044: }
045:
046: protected byte[] doTransform(ClassLoader loader, String className,
047: Class classBeingRedefined,
048: ProtectionDomain protectionDomain, byte[] classfileBuffer) {
049: ClassReader reader;
050: try {
051: reader = new ClassReader(new ByteArrayInputStream(
052: classfileBuffer));
053: } catch (IOException e) {
054: log.error("Unable to read class", e);
055: throw new HibernateException("Unable to read class: "
056: + e.getMessage());
057: }
058:
059: String[] names = ClassNameReader.getClassInfo(reader);
060: ClassWriter w = new DebuggingClassWriter(true);
061: ClassTransformer t = getClassTransformer(names);
062: if (t != null) {
063: if (log.isDebugEnabled()) {
064: log.debug("Enhancing " + className);
065: }
066: ByteArrayOutputStream out;
067: byte[] result;
068: try {
069: reader = new ClassReader(new ByteArrayInputStream(
070: classfileBuffer));
071: new TransformingClassGenerator(
072: new ClassReaderGenerator(reader, attributes(),
073: skipDebug()), t).generateClass(w);
074: out = new ByteArrayOutputStream();
075: out.write(w.toByteArray());
076: result = out.toByteArray();
077: out.close();
078: } catch (Exception e) {
079: log.error("Unable to transform class", e);
080: throw new HibernateException(
081: "Unable to transform class: " + e.getMessage());
082: }
083: return result;
084: }
085: return classfileBuffer;
086: }
087:
088: private Attribute[] attributes() {
089: return Attributes.getDefaultAttributes();
090: }
091:
092: private boolean skipDebug() {
093: return false;
094: }
095:
096: private ClassTransformer getClassTransformer(
097: final String[] classInfo) {
098: if (isAlreadyInstrumented(classInfo)) {
099: return null;
100: }
101: return new InterceptFieldTransformer(
102: new InterceptFieldFilter() {
103: public boolean acceptRead(Type owner, String name) {
104: return fieldFilter.shouldTransformFieldAccess(
105: classInfo[0], owner.getClassName(),
106: name);
107: }
108:
109: public boolean acceptWrite(Type owner, String name) {
110: return fieldFilter.shouldTransformFieldAccess(
111: classInfo[0], owner.getClassName(),
112: name);
113: }
114: });
115: }
116:
117: private boolean isAlreadyInstrumented(String[] classInfo) {
118: for (int i = 1; i < classInfo.length; i++) {
119: if (InterceptFieldEnabled.class.getName().equals(
120: classInfo[i])) {
121: return true;
122: }
123: }
124: return false;
125: }
126: }
|