//
// This file is part of the prose package.
//
// The contents of this file are subject to the Mozilla Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// The Original Code is prose.
//
// The Initial Developer of the Original Code is Andrei Popovici. Portions
// created by Andrei Popovici are Copyright (C) 2002 Andrei Popovici.
// All Rights Reserved.
//
// Contributor(s):
// $Id: SignaturePattern.java,v 1.3 2008/11/18 11:36:07 anicoara Exp $
// =====================================================================
//
package ch.ethz.prose.crosscut;
// used packages
import java.lang.reflect.Method;
import java.lang.Class;
/**
* Every Crosscut contains a method to be executed when a join-point is hit.
* In the case of <code>MethodCut</code> objects, the SignaturePattern has three
* roles:
* <ul>
* <li> The pattern role: through a special signature, define matches for the
* target class, and for the parameters of the methods belonging to the target.
*
* <li> The method finder role: determine which method o of the crosscut
* must be ivoked upon a hit join-point.
*
* <li> The optimization role: to cathegorize the signature of the advice
* method, such that the subsequent execution of the advice method is efficient.
* The categorization is currently performed according to the <code>SIGNATURE__XXX</code>
* constants.
* </ul>
*
* @version $Revision: 1.3 $
* @author Andrei Popovici
*/
public abstract class SignaturePattern {
// work constants bit 3 bit 2
protected final static int WILDCARD_1 = 0x02;
protected final static int WILDCARD_2 = 0x04;
protected final static int CONCRETE_1= 0x08;
protected final static int CONCRETE_2= 0x01;
/// constants reflecting the cathegory of the signature of <code>methodObj</code>
protected static final int SIGNATURE__WILDCARD__WILDCARD = WILDCARD_1 | WILDCARD_2;
protected static final int SIGNATURE__WILDCARD__CONCRETE = WILDCARD_1 | CONCRETE_2;
protected static final int SIGNATURE__CONCRETE__WILDCARD = CONCRETE_1 | WILDCARD_2;
protected static final int SIGNATURE__CONCRETE__CONCRETE = CONCRETE_1 | CONCRETE_2;
protected static final int SIGNATURE__ARBITRARY = 0;
protected static final int SIGNATURE__EMPTY = 0x1000;
/** The signature cathegory of <code>methodObj</code>.
*/
protected int signatureCathegory = SIGNATURE__ARBITRARY;
/** The method to be invoked upon reaching a joinpoint,
* or <code>null</code> if the enclosing
* Crosscut defines its own <code>adviceMethod</code>.
*/
protected transient Method methodObj = null;
/** The signature of <code>methodObj</code>, equivalent to
* <code>methodObj.getParameterTypes()</code>. Present
* for efficiency reasons.
*/
protected transient Class[] signature = null;
protected transient Class wildcardClass = null;
/**
* Return the number of arguments required by this advice.
*/
protected int getLength() {
return signature.length;
}
protected Class getReceiverType() {
if (signature.length == 0)
return null;
else
return signature[0];
}
/** When no advice action is set, it returns true.
* If an advice action exists, it returns true
* if the pattern-matching signature acepts <code>actualClass</code>
* as a potential crosscut class.
*/
protected boolean matchesTarget(Class actualClass) {
if (signatureCathegory == SIGNATURE__EMPTY)
return true;
else
return isAssignable(actualClass, signature[0]);
}
protected boolean isAssignable(Class actualParameterType, Class formalParameterType) throws Error {
if (Wildcard.class.isAssignableFrom(formalParameterType)) {
try {
if (((Wildcard)formalParameterType.newInstance()).isAssignableFrom(actualParameterType))
return true;
// the Wilcard specification states that wildcard classes
// should have an emtpy default constructor. If they
// don't have: it is a RUNES IMPLEMENTATION ERROR
}
catch (IllegalAccessException noConstructor) {
throw new Error(noConstructor.toString());
}
catch (InstantiationException wrongConstructor) {
throw new Error(wrongConstructor.toString());
}
return false;
}
//else if ( formalParameterType.isAssignableFrom(actualParameterType)) //BEFORE - BUGFIX - different class loaders (Tomcat)
// return true; //BEFORE - BUGFIX - different class loaders (Tomcat)
//else //BEFORE - BUGFIX - different class loaders (Tomcat)
// return false; //BEFORE - BUGFIX - different class loaders (Tomcat)
else { //PLUS - BUGFIX - different class loaders (Tomcat)
Class actualFormalParameterType = formalParameterType; //PLUS - BUGFIX
try { //PLUS - BUGFIX
actualFormalParameterType = actualParameterType.getClassLoader().loadClass(formalParameterType.getName()); //PLUS - BUGFIX
if (actualFormalParameterType == null) actualFormalParameterType = formalParameterType; //PLUS - BUGFIX
} catch(Exception e) { } //PLUS - BUGFIX
boolean result = (actualFormalParameterType.isAssignableFrom(actualParameterType)); //PLUS - BUGFIX
//System.err.println("SignaturePattern - isAssignable - Class => " + formalParameterType + " is assignable from " + actualFormalParameterType + ":" + result);
return result; //PLUS - BUGFIX
}
}
protected void initFromMethod(Class methodClass, String adviceName, Class wildcardClass,Class htop) {
this.wildcardClass = wildcardClass;
initAdviceMethod(methodClass,adviceName,htop);
signature = methodObj.getParameterTypes();
initSignatureCathegory();
}
private void initAdviceMethod(Class methodClass,String adviceName,Class hierarchyTop) {
int ambigousCnt = 0;
Method mObj = null;
Class crtClass = methodClass;
// look up a method with the name 'adviceName'; if such a method is found,
while (crtClass != null &&
!crtClass.equals(hierarchyTop) && // (e.g., crtClass != MethodCut)
hierarchyTop.isAssignableFrom(crtClass) && // (e.g., crtClass subclass of MethodCut)
mObj == null) {
Method[] methods = crtClass.getDeclaredMethods();
ambigousCnt = 0;
// we have to select some method
// try to match a method with such a name
for (int i=0; i < methods.length; i++)
if ( methods[i].getName().equals(adviceName)) {
mObj = methods[i];
ambigousCnt++;
}
crtClass=crtClass.getSuperclass();
}
if (mObj == null)
throw new MissingInformationException("No advice action specified");
if (ambigousCnt > 1)
throw new MissingInformationException("Two advice methods detected. Ambigous advice specification");
try {
mObj.setAccessible(true);
}
catch (SecurityException opaqueCrosscut) {
// this is not very likely to ocurr
}
methodObj = mObj;
}
private void initSignatureCathegory() {
Method m = methodObj;
int optimization = SIGNATURE__ARBITRARY;
Class[] adviceParamTypes = m.getParameterTypes();
if (adviceParamTypes.length == 0) {
signatureCathegory = SIGNATURE__EMPTY;
return;
}
// figure out whether the receiver is a wildcard
if (ANY.class.isAssignableFrom(adviceParamTypes[0]))
optimization |= WILDCARD_1;
else
optimization |= CONCRETE_1;
// figure out whether *all* parameters are wildcard
boolean restIsWildcard = true;
boolean restIsConcrete = true;
for (int i = 1; i < adviceParamTypes.length; i++) {
if (Wildcard.class.isAssignableFrom(adviceParamTypes[i]))
restIsConcrete = false;
else
restIsWildcard = false;
}
// and update the result
if (restIsWildcard && adviceParamTypes.length == 2 && adviceParamTypes[1].equals(wildcardClass))
optimization |= WILDCARD_2;
if (restIsConcrete)
optimization |= CONCRETE_2;
signatureCathegory = optimization;
}
protected boolean isAssignable(Class[] actualParameterType, Class formalParameterType) {
if (Wildcard.class.isAssignableFrom(formalParameterType)) {
try {
if (((Wildcard)formalParameterType.newInstance()).isAssignableFrom(actualParameterType))
return true;
}
catch (IllegalAccessException noConstructor) {
throw new Error(noConstructor.toString());
}
catch (InstantiationException wrongConstructor) {
throw new Error(wrongConstructor.toString());
}
return false;
}
else
return false;
}
}