org.aspectj.weaver.ShadowMunger Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.servicemix.bundles.aspectj
Show all versions of org.apache.servicemix.bundles.aspectj
This OSGi bundle wraps aspectjrt and aspectjweaver ${pkgVersion} jar files.
/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* 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:
* PARC initial implementation
* ******************************************************************/
package org.aspectj.weaver;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.util.PartialOrder;
import org.aspectj.weaver.patterns.PerClause;
import org.aspectj.weaver.patterns.Pointcut;
import org.aspectj.weaver.patterns.TypePattern;
/**
* For every shadow munger, nothing can be done with it until it is concretized. Then...
*
* (Then we call fast match.)
*
* For every shadow munger, for every shadow, first match is called, then (if match returned true) the shadow munger is specialized
* for the shadow, which may modify state. Then implement is called.
*/
public abstract class ShadowMunger implements PartialOrder.PartialComparable, IHasPosition {
public static final ShadowMunger[] NONE = new ShadowMunger[0];
private static int VERSION_1 = 1; // ShadowMunger version for serialization
protected static final int ShadowMungerAdvice = 1;
protected static final int ShadowMungerDeow = 2;
public String handle = null;
private int shadowMungerKind;
protected int start, end;
protected ISourceContext sourceContext;
private ISourceLocation sourceLocation;
private ISourceLocation binarySourceLocation;
private File binaryFile;
private ResolvedType declaringType;
private boolean isBinary;
private boolean checkedIsBinary;
protected Pointcut pointcut;
protected ShadowMunger() {
}
public ShadowMunger(Pointcut pointcut, int start, int end, ISourceContext sourceContext, int shadowMungerKind) {
this.shadowMungerKind = shadowMungerKind;
this.pointcut = pointcut;
this.start = start;
this.end = end;
this.sourceContext = sourceContext;
}
/**
* All overriding methods should call super
*/
public boolean match(Shadow shadow, World world) {
if (world.isXmlConfigured() && world.isAspectIncluded(declaringType)) {
TypePattern scoped = world.getAspectScope(declaringType);
if (scoped != null) {
// Check the 'cached' exclusion map
Set excludedTypes = world.getExclusionMap().get(declaringType);
ResolvedType type = shadow.getEnclosingType().resolve(world);
if (excludedTypes != null && excludedTypes.contains(type)) {
return false;
}
boolean b = scoped.matches(type, TypePattern.STATIC).alwaysTrue();
if (!b) {
if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) {
world.getMessageHandler().handleMessage(
MessageUtil.info("Type '" + type.getName() + "' not woven by aspect '" + declaringType.getName()
+ "' due to scope exclusion in XML definition"));
}
if (excludedTypes == null) {
excludedTypes = new HashSet<>();
excludedTypes.add(type);
world.getExclusionMap().put(declaringType, excludedTypes);
} else {
excludedTypes.add(type);
}
return false;
}
}
}
if (world.areInfoMessagesEnabled() && world.isTimingEnabled()) {
long starttime = System.nanoTime();
FuzzyBoolean isMatch = pointcut.match(shadow);
long endtime = System.nanoTime();
world.record(pointcut, endtime - starttime);
return isMatch.maybeTrue();
} else {
FuzzyBoolean isMatch = pointcut.match(shadow);
return isMatch.maybeTrue();
}
}
public int fallbackCompareTo(Object other) {
return toString().compareTo(toString());
}
public int getEnd() {
return end;
}
public int getStart() {
return start;
}
public ISourceLocation getSourceLocation() {
if (sourceLocation == null) {
if (sourceContext != null) {
sourceLocation = sourceContext.makeSourceLocation(this);
}
}
if (isBinary()) {
if (binarySourceLocation == null) {
binarySourceLocation = getBinarySourceLocation(sourceLocation);
}
return binarySourceLocation;
}
return sourceLocation;
}
public Pointcut getPointcut() {
return pointcut;
}
// pointcut may be updated during rewriting...
public void setPointcut(Pointcut pointcut) {
this.pointcut = pointcut;
}
/**
* Invoked when the shadow munger of a resolved type are processed.
*
* @param aType
*/
public void setDeclaringType(ResolvedType aType) {
declaringType = aType;
}
public ResolvedType getDeclaringType() {
return declaringType;
}
public abstract ResolvedType getConcreteAspect();
/**
* Returns the binarySourceLocation for the given sourcelocation. This isn't cached because it's used when faulting in the
* binary nodes and is called with ISourceLocations for all advice, pointcuts and deows contained within the
* resolvedDeclaringAspect.
*/
public ISourceLocation getBinarySourceLocation(ISourceLocation sl) {
if (sl == null) {
return null;
}
String sourceFileName = null;
if (getDeclaringType() instanceof ReferenceType) {
String s = ((ReferenceType) getDeclaringType()).getDelegate().getSourcefilename();
int i = s.lastIndexOf('/');
if (i != -1) {
sourceFileName = s.substring(i + 1);
} else {
sourceFileName = s;
}
}
ISourceLocation sLoc = new SourceLocation(getBinaryFile(), sl.getLine(), sl.getEndLine(),
((sl.getColumn() == 0) ? ISourceLocation.NO_COLUMN : sl.getColumn()), sl.getContext(), sourceFileName);
return sLoc;
}
/**
* Returns the File with pathname to the class file, for example either:
* C:\temp \ajcSandbox\workspace\ajcTest16957.tmp\simple.jar!pkg\BinaryAspect.class if the class file is in a jar file, or
* C:\temp\ajcSandbox\workspace\ajcTest16957.tmp!pkg\BinaryAspect.class if the class file is in a directory
*/
private File getBinaryFile() {
if (binaryFile == null) {
String binaryPath = getDeclaringType().getBinaryPath();
if (binaryPath == null) {
// Looks like an aspect that has been picked up from the classpath (likely an abstract one
// being extended). As it didn't come in via inpath or aspectpath the binarypath has not
// yet been constructed.
// We can't discover where the file came from now, that info has been lost. So just
// use "classpath" for now - until we discover we need to get this right.
binaryPath = "classpath";
getDeclaringType().setBinaryPath(binaryPath);
// ReferenceTypeDelegate delegate = ((ReferenceType) getDeclaringType()).getDelegate();
// if (delegate instanceof BcelObjectType) {
// grab javaclass... but it doesnt know the originating file
// }
}
if (!binaryPath.contains("!")) {
File f = getDeclaringType().getSourceLocation().getSourceFile();
// Replace the source file suffix with .class
int i = f.getPath().lastIndexOf('.');
String path = null;
if (i != -1) {
path = f.getPath().substring(0, i) + ".class";
} else {
path = f.getPath() + ".class";
}
binaryFile = new File(binaryPath + "!" + path);
} else {
binaryFile = new File(binaryPath);
}
}
return binaryFile;
}
/**
* Returns whether or not this shadow munger came from a binary aspect - keep a record of whether or not we've checked if we're
* binary otherwise we keep calculating the same thing many times
*/
public boolean isBinary() {
if (!checkedIsBinary) {
ResolvedType rt = getDeclaringType();
if (rt != null) {
isBinary = ((rt.getBinaryPath() == null) ? false : true);
}
checkedIsBinary = true;
}
return isBinary;
}
public abstract ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause);
public abstract void specializeOn(Shadow shadow);
/**
* Implement this munger at the specified shadow, returning a boolean to indicate success.
*
* @param shadow the shadow where this munger should be applied
* @return true if the implement was successful
*/
public abstract boolean implementOn(Shadow shadow);
public abstract ShadowMunger parameterizeWith(ResolvedType declaringType, Map typeVariableMap);
/**
* @return a Collection of ResolvedTypes for all checked exceptions that might be thrown by this munger
*/
public abstract Collection getThrownExceptions();
/**
* Does the munger have to check that its exception are accepted by the shadow ? It is not the case for annotation style around
* advice, for example: that can throw Throwable, even if the advised method does not throw any exceptions.
*
* @return true if munger has to check that its exceptions can be thrown based on the shadow
*/
public abstract boolean mustCheckExceptions();
public void write(CompressingDataOutputStream stream) throws IOException {
stream.writeInt(VERSION_1);
stream.writeInt(shadowMungerKind); // determines real subclass
stream.writeInt(start);
stream.writeInt(end);
PersistenceSupport.write(stream, sourceContext);
PersistenceSupport.write(stream, sourceLocation);
PersistenceSupport.write(stream, binarySourceLocation);
PersistenceSupport.write(stream, binaryFile);
declaringType.write(stream);
stream.writeBoolean(isBinary);
stream.writeBoolean(checkedIsBinary);
pointcut.write(stream);
}
//
// public static ShadowMunger read(VersionedDataInputStream stream, World world) throws IOException {
// stream.readInt();
// int kind = stream.readInt();
// ShadowMunger newShadowMunger = null;
// switch (kind) {
// case ShadowMungerAdvice:
// // world.getWeavingSupport().createAdviceMunger(attribute, pointcut, signature)
// case ShadowMungerDeow:
// newShadowMunger = Checker.read(stream, world);
// default:
// throw new IllegalStateException("Unexpected type of shadow munger found on deserialization: " + kind);
// }
// newShadowMunger.binaryFile = null;
// }
public boolean bindsProceedingJoinPoint() {
return false;
}
public boolean isAroundAdvice() {
return false;
}
}