/* *******************************************************************
 * Copyright (c) 2005 Contributors.
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *   Ron Bodkin		Initial implementation
 * ******************************************************************/
package org.aspectj.weaver.ltw;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.util.LangUtil;
import org.aspectj.weaver.Dump.IVisitor;
import org.aspectj.weaver.ICrossReferenceHandler;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ReferenceTypeDelegate;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.bcel.BcelWorld;
import org.aspectj.weaver.loadtime.IWeavingContext;
import org.aspectj.weaver.reflect.AnnotationFinder;
import org.aspectj.weaver.reflect.IReflectionWorld;
import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegateFactory;
import org.aspectj.weaver.reflect.ReflectionWorld;

Author:adrian, Ron Bodkin For use in LT weaving Backed by both a BcelWorld and a ReflectionWorld Needs a callback when a woven class is defined This is the trigger for us to ditch the class from Bcel and cache it in the reflective world instead. Create by passing in a classloader, message handler
/** * @author adrian * @author Ron Bodkin * * For use in LT weaving * * Backed by both a BcelWorld and a ReflectionWorld * * Needs a callback when a woven class is defined This is the trigger for us to ditch the class from Bcel and cache it in * the reflective world instead. * * Create by passing in a classloader, message handler */
public class LTWWorld extends BcelWorld implements IReflectionWorld { private AnnotationFinder annotationFinder; private IWeavingContext weavingContext; private String classLoaderString; private String classLoaderParentString; protected final static Class concurrentMapClass; private static final boolean ShareBootstrapTypes = false; protected static Map/* <String, WeakReference<ReflectionBasedReferenceTypeDelegate>> */bootstrapTypes; static { if (ShareBootstrapTypes) { concurrentMapClass = makeConcurrentMapClass(); bootstrapTypes = makeConcurrentMap(); } else { concurrentMapClass = null; } }
Build a World from a ClassLoader, for LTW support
/** * Build a World from a ClassLoader, for LTW support */
public LTWWorld(ClassLoader loader, IWeavingContext weavingContext, IMessageHandler handler, ICrossReferenceHandler xrefHandler) { super(loader, handler, xrefHandler); this.weavingContext = weavingContext; try { classLoaderString = loader.toString(); } catch (Throwable t) { // Possibly some state in the loader isn't initialized but is used in the toString() classLoaderString = loader.getClass().getName()+":"+Integer.toString(System.identityHashCode(loader)); } classLoaderParentString = (loader.getParent() == null ? "<NullParent>" : loader.getParent().toString()); setBehaveInJava5Way(LangUtil.is15VMOrGreater()); annotationFinder = ReflectionWorld.makeAnnotationFinderIfAny(loader, this); } public ClassLoader getClassLoader() { return weavingContext.getClassLoader(); } // TEST // this is probably easier: just mark anything loaded while loading aspects as not // expendible... it also fixes a possible bug whereby non-rewoven aspects are deemed expendible // <exclude within="org.foo.aspects..*"/> // protected boolean isExpendable(ResolvedType type) { // return ((type != null) && !loadingAspects && !type.isAspect() && (!type // .isPrimitiveType())); // }
@Override
/** * @Override */
@Override protected ReferenceTypeDelegate resolveDelegate(ReferenceType ty) { // use reflection delegates for all bootstrap types ReferenceTypeDelegate bootstrapLoaderDelegate = resolveIfBootstrapDelegate(ty); if (bootstrapLoaderDelegate != null) { return bootstrapLoaderDelegate; } return super.resolveDelegate(ty); } protected ReferenceTypeDelegate resolveIfBootstrapDelegate(ReferenceType ty) { // first check for anything available in the bootstrap loader: these types are just defined from that without allowing // nondelegation // if (!ShareBootstrapTypes) return null; // String name = ty.getName(); // Reference bootRef = (Reference) bootstrapTypes.get(name); // if (bootRef != null) { // ReferenceTypeDelegate rtd = (ReferenceTypeDelegate) bootRef.get(); // if (rtd != null) { // return rtd; // } // } // // char fc = name.charAt(0); // if (fc == 'j' || fc == 'c' || fc == 'o' || fc == 's') { // cheaper than imminent string startsWith tests // if (name.startsWith("java") || name.startsWith("com.sun.") || name.startsWith("org.w3c") || // name.startsWith("sun.") || name.startsWith("org.omg")) { // ReferenceTypeDelegate bootstrapLoaderDelegate = resolveReflectionTypeDelegate(ty, null); // if (bootstrapLoaderDelegate != null) { // // it's always fine to load these bytes: there's no weaving into them // // and since the class isn't initialized, all we are doing at this point is loading the bytes // // processedRefTypes.put(ty, this); // has no effect - and probably too aggressive if we did store // // these in the type map // // // should we share these, like we do the BCEL delegates? // bootstrapTypes.put(ty.getName(), new WeakReference(bootstrapLoaderDelegate)); // } // return bootstrapLoaderDelegate; // } // } return null; }
Helper method to resolve the delegate from the reflection delegate factory.
/** * Helper method to resolve the delegate from the reflection delegate factory. */
private ReferenceTypeDelegate resolveReflectionTypeDelegate(ReferenceType ty, ClassLoader resolutionLoader) { ReferenceTypeDelegate res = ReflectionBasedReferenceTypeDelegateFactory.createDelegate(ty, this, resolutionLoader); return res; }
Remove this class from the typeMap. Call back to be made from a publishing class loader The class loader should, ideally, make this call on each not yet working
Params:
  • clazz –
/** * Remove this class from the typeMap. Call back to be made from a publishing class loader The class loader should, ideally, * make this call on each not yet working * * @param clazz */
public void loadedClass(Class clazz) { } private static final long serialVersionUID = 1; public AnnotationFinder getAnnotationFinder() { return this.annotationFinder; } /* * (non-Javadoc) * * @see org.aspectj.weaver.reflect.IReflectionWorld#resolve(java.lang.Class) */ public ResolvedType resolve(Class aClass) { return ReflectionWorld.resolve(this, aClass); } private static Map makeConcurrentMap() { if (concurrentMapClass != null) { try { return (Map) concurrentMapClass.newInstance(); } catch (InstantiationException ie) { } catch (IllegalAccessException iae) { } // fall through if exceptions } return Collections.synchronizedMap(new HashMap()); } private static Class makeConcurrentMapClass() { String betterChoices[] = { "java.util.concurrent.ConcurrentHashMap", "edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap", "EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap" }; for (int i = 0; i < betterChoices.length; i++) { try { return Class.forName(betterChoices[i]); } catch (ClassNotFoundException cnfe) { // try the next one } catch (SecurityException se) { // you get one of these if you dare to try to load an undefined class in a // package starting with java like java.util.concurrent } } return null; } @Override public boolean isRunMinimalMemory() { if (isRunMinimalMemorySet()) { return super.isRunMinimalMemory(); } return false; } // One type is completed at a time, if multiple need doing then they // are queued up private boolean typeCompletionInProgress = false; private List/* ResolvedType */typesForCompletion = new ArrayList(); @Override protected void completeBinaryType(ResolvedType ret) { if (isLocallyDefined(ret.getName())) { if (typeCompletionInProgress) { typesForCompletion.add(ret); } else { try { typeCompletionInProgress = true; completeHierarchyForType(ret); } finally { typeCompletionInProgress = false; } while (typesForCompletion.size() != 0) { ResolvedType rt = (ResolvedType) typesForCompletion.get(0); completeHierarchyForType(rt); typesForCompletion.remove(0); } } } else { if (!ret.needsModifiableDelegate()) { ret = completeNonLocalType(ret); } } } private void completeHierarchyForType(ResolvedType ret) { getLint().typeNotExposedToWeaver.setSuppressed(true); weaveInterTypeDeclarations(ret); getLint().typeNotExposedToWeaver.setSuppressed(false); } protected boolean needsCompletion() { return true; } @Override public boolean isLocallyDefined(String classname) { return weavingContext.isLocallyDefined(classname); } protected ResolvedType completeNonLocalType(ResolvedType ret) { if (ret.isMissing()) { return ret; // who knows ?!? } ResolvedType toResolve = ret; if (ret.isParameterizedType() || ret.isGenericType()) { toResolve = toResolve.getGenericType(); } ReferenceTypeDelegate rtd = resolveReflectionTypeDelegate((ReferenceType) toResolve, getClassLoader()); ((ReferenceType) ret).setDelegate(rtd); return ret; } @Override public void storeClass(JavaClass clazz) { ensureRepositorySetup(); delegate.storeClass(clazz); } @Override public void accept(IVisitor visitor) { visitor.visitObject("Class loader:"); visitor.visitObject(classLoaderString); visitor.visitObject("Class loader parent:"); visitor.visitObject(classLoaderParentString); super.accept(visitor); } public boolean isLoadtimeWeaving() { return true; } }