All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.weaver.ltw.LTWWorld Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/* *******************************************************************
 * Copyright (c) 2005 Contributors.
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * Contributors:
 *   Ron Bodkin		Initial implementation
 * ******************************************************************/
package org.aspectj.weaver.ltw;

import java.lang.reflect.InvocationTargetException;
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.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
 * @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/* > */bootstrapTypes;

	static {
		if (ShareBootstrapTypes) {
			concurrentMapClass = makeConcurrentMapClass();
			bootstrapTypes = makeConcurrentMap();
		} else {
			concurrentMapClass = null;
		}
	}

	/**
	 * 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 ? "" : loader.getParent().toString());
		setBehaveInJava5Way(true);
		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
	// 
	// protected boolean isExpendable(ResolvedType type) {
	// return ((type != null) && !loadingAspects && !type.isAspect() && (!type
	// .isPrimitiveType()));
	// }

	/**
	 * 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.
	 */
	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
	 *
	 * @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.getDeclaredConstructor().newInstance();
			} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException ignored) {}
			// 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 (String betterChoice : betterChoices) {
			try {
				return Class.forName(betterChoice);
			} 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 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 = 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;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy