EclipseMEClassLoadingHook.java

Index Score
eclipseme.core.hooks
EclipseME

View: Reasons, Metrics, Source Code

These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.

MetricDescription
/** * Copyright (c) 2003-2006 Craig Setera * All Rights Reserved. * Licensed under the Eclipse Public License - v 1.0 * For more information see http://www.eclipse.org/legal/epl-v10.html */ package eclipseme.core.hooks; import java.io.PrintWriter; import java.io.StringWriter; import java.security.ProtectionDomain; import java.util.ArrayList; import org.eclipse.osgi.baseadaptor.BaseData; import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook; import org.eclipse.osgi.baseadaptor.loader.BaseClassLoader; import org.eclipse.osgi.baseadaptor.loader.ClasspathEntry; import org.eclipse.osgi.baseadaptor.loader.ClasspathManager; import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain; import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; import org.eclipse.osgi.framework.internal.core.BundleLoader; import org.eclipse.osgi.util.ManifestElement; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.util.TraceClassVisitor; import org.osgi.framework.BundleException; /** * Hooks the classloading functionality for EclipseME functionality. * <p /> * Copyright (c) 2003-2006 Craig Setera<br> * All Rights Reserved.<br> * Licensed under the Eclipse Public License - v 1.0<p/> * <br> * $Revision: 1.1 $ * <br> * $Date: 2007/01/19 01:38:10 $ * <br> * @author Craig Setera */ public class EclipseMEClassLoadingHook implements ClassLoadingHook { private static final String SOURCE_FILE_CLASS = "org.eclipse.jdt.internal.core.builder.SourceFile"; // Type reference to the IFile interface private static Type IFile_Type = Type.getType("Lorg/eclipse/core/resources/IFile;"); // Type reference to the JDT SourceFile class private static Type SourceFile_Type = Type.getType("Lorg/eclipse/jdt/internal/core/builder/SourceFile;"); // Type reference to the SourceMapperAccess type private static String SOURCE_MAPPER_CLASS = "eclipseme.core.hook.sourceMapper.SourceMapperAccess"; private static Type SourceMapperAccess_Type = Type.getType("Leclipseme/core/hook/sourceMapper/SourceMapperAccess;"); /** * Class adapter for rewriting the get contents method. */ class SourceFileClassAdapter extends ClassAdapter { /** * Construct a new adapter instance. * * @param cv */ public SourceFileClassAdapter(ClassVisitor cv) { super(cv); } /** * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) */ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions); if (name.equals("getContents")) { if (Debug.DEBUG_GENERAL) { System.out.println("SourceFile#getContents spotted. Rewriting method."); } methodVisitor = new GetContentsMethodVisitor(methodVisitor); } return methodVisitor; } } /** * Class adapter for rewriting the SourceMapperAccess class */ class SourceMapperAccessClassAdapter extends ClassAdapter { /** * Construct a new adapter instance. * * @param cv */ public SourceMapperAccessClassAdapter(ClassVisitor cv) { super(cv); } /** * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) */ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions); if (name.equals("isHookCodeInstalled")) { if (Debug.DEBUG_GENERAL) { System.out.println("SourceMapperAccess#isHookInstalled spotted. Rewriting method."); } methodVisitor = new IsHookInstalledMethodVisitor(methodVisitor); } return methodVisitor; } } /** * MethodVisitor implementation to rewrite the getContents method of * the SourceFile class. */ class GetContentsMethodVisitor extends MethodAdapter { boolean foundReturn = false; public GetContentsMethodVisitor(MethodVisitor mv) { super(mv); } /** * @see org.objectweb.asm.MethodAdapter#visitFieldInsn(int, java.lang.String, java.lang.String, java.lang.String) */ public void visitFieldInsn(int opcode, String owner, String name, String desc) { if ((opcode == Opcodes.GETFIELD) && (name.equals("resource")) && !foundReturn) { insertMappedResourceCode(); } else { super.visitFieldInsn(opcode, owner, name, desc); } } /** * @see org.objectweb.asm.MethodAdapter#visitInsn(int) */ public void visitInsn(int opcode) { if (!foundReturn && (opcode == Opcodes.ARETURN)) { if (Debug.DEBUG_GENERAL) { System.out.println("Found ARETURN in method."); } foundReturn = true; } super.visitInsn(opcode); } /** * Insert the code that will attempt to request the mapped * resource from the {@link SourceMapperTracker}. */ private void insertMappedResourceCode() { if (Debug.DEBUG_GENERAL) { System.out.println("Inserting mapped resource lookup code into method."); } // We want to rewrite the first GETFIELD call for the resource // object as a call to the mapping function Label endLabel = new Label(); // Call through the mapper accessor to see if we // get a mapped resource insertDebugMessageCode("Rewritten SourceFile"); super.visitInsn(Opcodes.POP); super.visitVarInsn(Opcodes.ALOAD, 0); // Load "this" super.visitFieldInsn( Opcodes.GETFIELD, SourceFile_Type.getInternalName(), "resource", IFile_Type.getDescriptor()); super.visitMethodInsn( Opcodes.INVOKESTATIC, SourceMapperAccess_Type.getInternalName(), "getMappedSourceFile", Type.getMethodDescriptor(IFile_Type, new Type[] { IFile_Type })); // If the result was non-null, we are done... otherwise we need to // clear the extra copy and load the raw resource super.visitInsn(Opcodes.DUP); super.visitJumpInsn(Opcodes.IFNONNULL, endLabel); insertDebugMessageCode("Mapped resource was null"); super.visitInsn(Opcodes.POP); // Load the local (raw) resource insertDebugMessageCode("Using raw resource"); super.visitVarInsn(Opcodes.ALOAD, 0); // Load "this" super.visitFieldInsn( Opcodes.GETFIELD, SourceFile_Type.getInternalName(), "resource", IFile_Type.getDescriptor()); // All done with the rewrite visitLabel(endLabel); insertDebugMessageCode("Finished generated code"); } /** * Write the code that will write a debug message. * * @param message */ private void insertDebugMessageCode(String message) { if (Debug.DEBUG_GENERAL) { super.visitFieldInsn( Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); super.visitLdcInsn(message); super.visitMethodInsn( Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); } } } /** * MethodVisitor implementation to rewrite the isHookInstalled method of * the SourceMapperAccess class. */ class IsHookInstalledMethodVisitor extends MethodAdapter { public IsHookInstalledMethodVisitor(MethodVisitor mv) { super(mv); } public void visitInsn(int opcode) { if (opcode == Opcodes.ICONST_0) { opcode = Opcodes.ICONST_1; } super.visitInsn(opcode); } } /** * @see org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook#addClassPathEntry(java.util.ArrayList, java.lang.String, org.eclipse.osgi.baseadaptor.loader.ClasspathManager, org.eclipse.osgi.baseadaptor.BaseData, java.security.ProtectionDomain) */ public boolean addClassPathEntry( ArrayList cpEntries, String cp, ClasspathManager hostmanager, BaseData sourcedata, ProtectionDomain sourcedomain) { return false; } /** * @see org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook#createClassLoader(java.lang.ClassLoader, org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate, org.eclipse.osgi.framework.adaptor.BundleProtectionDomain, org.eclipse.osgi.baseadaptor.BaseData, java.lang.String[]) */ public BaseClassLoader createClassLoader( ClassLoader parent, ClassLoaderDelegate delegate, BundleProtectionDomain domain, BaseData data, String[] bundleclasspath) { boolean isJdtCore = "org.eclipse.jdt.core".equals(data.getSymbolicName()); boolean isEclipseBundleLoader = delegate instanceof BundleLoader; // If the bundle loader is of the corrent type and is for // the JDT core bundle, we will go ahead and force an OSGi "wire" // back to our package implementation from the JDT plugin. if (isEclipseBundleLoader && isJdtCore) { if (Debug.DEBUG_GENERAL) { System.out.println("Adding dynamic import into JDT Core bundle"); } try { ManifestElement[] dynamicElements = ManifestElement.parseHeader( "DynamicImport-Package", "eclipseme.core.hook.sourceMapper"); ((BundleLoader) delegate).addDynamicImportPackage(dynamicElements); } catch (BundleException e) { if (Debug.DEBUG_GENERAL) { e.printStackTrace(); } } } // Let the framework know that we did not create the classloader return null; } /** * @see org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook#findLibrary(org.eclipse.osgi.baseadaptor.BaseData, java.lang.String) */ public String findLibrary(BaseData data, String libName) { // Do nothing return null; } /** * @see org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook#getBundleClassLoaderParent() */ public ClassLoader getBundleClassLoaderParent() { // Do nothing return null; } /** * @see org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook#initializedClassLoader(org.eclipse.osgi.baseadaptor.loader.BaseClassLoader, org.eclipse.osgi.baseadaptor.BaseData) */ public void initializedClassLoader(BaseClassLoader baseClassLoader, BaseData data) { // Do nothing } /** * @see org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook#processClass(java.lang.String, byte[], org.eclipse.osgi.baseadaptor.loader.ClasspathEntry, org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry, org.eclipse.osgi.baseadaptor.loader.ClasspathManager) */ public byte[] processClass( String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { byte[] processed = null; if (SOURCE_FILE_CLASS.equals(name) || SOURCE_MAPPER_CLASS.equals(name)) { processed = rewriteSourceFileClass(name, classbytes); } return processed; } /** * Rewrite the SourceFile class given the specified class bytes. * * @param classBytes * @return */ private byte[] rewriteSourceFileClass(String name, byte[] classBytes) { byte[] rewritten = classBytes; if (Debug.DEBUG_GENERAL) { System.out.println(name + " located. Rewriting class bytes."); } // Use ASM to rewrite the SourceFile.getMethods call ClassReader classReader = new ClassReader(classBytes); ClassWriter classWriter = new ClassWriter(true); ClassAdapter adapter = null; if (SOURCE_FILE_CLASS.equals(name)) { adapter = new SourceFileClassAdapter(classWriter); } else { adapter = new SourceMapperAccessClassAdapter(classWriter); } classReader.accept(adapter, false); rewritten = classWriter.toByteArray(); // Dump the rewritten class file if debug is enabled if (Debug.DEBUG_GENERAL) { StringWriter stringWriter = new StringWriter(); ClassReader reader = new ClassReader(rewritten); TraceClassVisitor writer = new TraceClassVisitor(new PrintWriter(stringWriter)); reader.accept(writer, true); System.out.println(stringWriter); } return rewritten; } }

The table below shows all metrics for EclipseMEClassLoadingHook.java.

MetricValueDescription