//
// 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 Angela Nicoara. Portions
// created by Angela Nicoara are Copyright (C) 2004 Angela Nicoara.
// All Rights Reserved.
//
// Contributor(s):
// $Id: ConstructorCut.java,v 1.2 2008/11/18 11:36:07 anicoara Exp $
// =====================================================================
//
package ch.ethz.prose.crosscut;
// used packages
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import ch.ethz.jvmai.JoinPoint;
import ch.ethz.prose.engine.JoinPointRequest;
import ch.ethz.jvmai.ConstructorJoinPoint;
import ch.ethz.prose.filter.ANDingPointCutter;
import ch.ethz.prose.filter.PointCutter;
/**
* Class ConstructorCut represents a crosscut. Such a crosscut
* defines a pattern (for matching specific join-points) and a method
* to be executed. Users must subclass <code>ConstructorCut</code>.
* There are two main modalities for subclassing:
* <h3>The typical way (normal user)</h3>
* Define exactly one method (e.g., <code>METHOD_ARGS(Bar thisO,Baz param1)</code>).
* This method is both the advice action to be executed and it defines
* a pattern. Thus, just entries and exits of invocations of the form
* <code>Bar.*(Baz)</code> will be considered join-points of this
* crosscut.
* <p>
* This crosscut defines a crosscut for all entry-
* points of the matched constructor.
* <p>
* Use <code>pointCutter</code> to further restrict the number of
* points were advices are executed.
*
* @version $Revision: 1.2 $
* @author Angela Nicoara
* @author Gerald Linhofer
*/
public abstract class ConstructorCut extends AbstractCrosscut implements java.io.Serializable {
///////////////////////////////////////////////////////////////////////////////////////////
/// THE CROSSCUT: ADVICE METHOD + ADVICE EXECUTION put together
///////////////////////////////////////////////////////////////////////////////////////////
/**
* Override the value of this variable if you want to change the
* name of the method wildcards.
*/
public void METHOD_ARGS(){}
/**
* If you have more than one method in this class, determining the
* name of the advice method will use the value of this method. This
* variable should then be initialized with the name of the method
* you want to call as advice method.
*/
transient boolean isInitialized = false;
transient ConstructorCutSpecializer ccutSpecializer = null;
transient ConstructorCutSignaturePattern adviceSignature = null;
String toStringSignature;
private void initState() throws MissingInformationException {
if (isInitialized) return;
isInitialized=true;
adviceSignature = new ConstructorCutSignaturePattern(this);
ccutSpecializer = new ConstructorCutSpecializer(adviceSignature);
toStringSignature = adviceSignature.toString();
}
/**
* We want people to subclass this class.
* Create a <code>ConstructorCut</code> object.
*
* @throws MissingInformationException this crosscut does
* not define an advice method / or does not override methodAdvice.
*/
protected ConstructorCut() throws MissingInformationException {
initState();
}
public void insertionAction(boolean beforeInsertion) {
super.insertionAction(beforeInsertion);
// we might provide an initstate here for the case
// this crosscut is deserialized and the
// static initializer or the constructor are not properly
// called
initState();
}
/**
* Return all potential classes to which this crosscut applies:
* To all loaded classes, apply the <code>isPotentialCrosscutClass</code>
* selector.
*/
protected Class[] potentialCrosscutClasses() throws MissingInformationException {
// get exactly one method declared in this class with more
// than one argument
Class[] result = new Class[]{};
List searchList = new Vector(Arrays.asList(super.potentialCrosscutClasses()));
// if the receiver class is not a wildcard, we add the
// receiver class to the potential crosscut classes
Class receiverClass=adviceSignature.getReceiverType();
if (receiverClass!= null && !Wildcard.class.isAssignableFrom(receiverClass) &&
!searchList.contains(receiverClass))
searchList.add(receiverClass);
Vector resultList = new Vector();
// then we search in the search list
Iterator i = searchList.iterator();
while (i.hasNext()) {
Class crtCls=(Class)i.next();
if (isPotentialCrosscutClass(crtCls))
resultList.add(crtCls);
}
// and return the corresponding array
result = (Class[])resultList.toArray(new Class[]{});
return result;
}
/** Return true only if
* <ol>
* <li> This crosscut redefines the <code>methodAdvice</code> method, <em>OR</em>
* <li> if this crosscut defines an advice, and the corresponding <code>UserDefinedMCSignature</code>
* matches the target class <code>crtCls</code>.
* </ol>
*/
protected boolean isPotentialCrosscutClass(Class crtCls) throws MissingInformationException {
return adviceSignature.matchesTarget(crtCls);
}
/**
* Retrieve those constructors belonging to <code>theClass</code>
* which have the same signature as the advice methods. Use the
* <code>UserDefinedMCSignature</code> object (<code>adviceSignature</code>)
* to determine which constructors defined in class <code>theClass</code>
* match the pattern.
* (if wildcards are present, they use them to match more constructors in <code>theClass</code>)
* <p>
* Return a list of <code>JoinPointRequest</code> objects corresponding
* to all locations of the matched constructors.
* <p>
* <em>This implementation will return just Constructor-Entry locations.</em>.
*/
protected CrosscutRequest doCreateRequest(Class theClass) {
//1. retrieve those constructors TCM belonging to class theClass
// for which the following holds:
// if M[i] is not a wildcard, M[i] is assignable from TCM[i]
// if M[i] is a wildcard, TCM[i] matches M[i] or
// TCM[i..TCM.lenth] matches M[i]
CrosscutRequest result = new CrosscutRequest();
//take the constructors declared in the given class only (ignore
//inherited constructors!)
//A possible problem might occur because of the access control
Constructor[] constructorArray = null;
try { constructorArray = theClass.getDeclaredConstructors(); }
catch (NoClassDefFoundError e) {
return result;
}
for(int i=0; i<constructorArray.length; i++) {
Class[] params = constructorArray[i].getParameterTypes();
JoinPointRequest crtRequest;
crtRequest = requestFactory.createJoinPointRequest(ConstructorJoinPoint.KIND,constructorArray[i]);
if (ccutSpecializer.isSpecialRequest(crtRequest))
result.add(crtRequest);
}
return result;
}
/**
* Create an action to execute the advice which matched the
* constructor in which the location of <code>jpe</code> resides.
*
* @exception InvocationTargetException some error occured inside
* the advice method.
* @exception IllegalAccessException the advice method was not public
*/
public void joinPointAction(ConstructorJoinPoint ev) throws IllegalAccessException, InvocationTargetException {
constructorAdvice(ev);
}
// /**
// * Create an action to execute the advice which matched the
// * method in which the location of <code>jpe</code> resides.
// *
// * @exception InvocationTargetException some error occured inside
// * the advice method.
// * @exception IllegalAccessException the advice method was not public
// */
// public void joinPointAction(MethodExitJoinPoint ev) throws IllegalAccessException, InvocationTargetException
// {
// // call advice
// methodAdvice(ev);
// }
//
//
/**
* If 'constructorAdvice' has been redefined, then we will deal with a
* 'DefaultMcutSignature'. But in THAT case, this method
* will be never executed.
*
*/
private void constructorAdvice(JoinPoint joinPoint)
throws InvocationTargetException, IllegalAccessException {
// create the appropriate 'adviceExecutionObject';
CcutAdvice toRun= null;
switch(adviceSignature.signatureCathegory) {
case SignaturePattern.SIGNATURE__EMPTY:
METHOD_ARGS();
break;
case SignaturePattern.SIGNATURE__CONCRETE__CONCRETE:
toRun = new ConcreteConcreteCcutAdvice(this, joinPoint,(ConstructorCutSignaturePattern)adviceSignature);
break;
case SignaturePattern.SIGNATURE__WILDCARD__CONCRETE:
toRun = new WildcardConcreteCcutAdvice(this, joinPoint,(ConstructorCutSignaturePattern)adviceSignature);
break;
case SignaturePattern.SIGNATURE__WILDCARD__WILDCARD:
toRun = new WildcardWildcardCcutAdvice(this, joinPoint,(ConstructorCutSignaturePattern)adviceSignature);
break;
case SignaturePattern.SIGNATURE__CONCRETE__WILDCARD:
toRun = new ConcreteWildcardCcutAdvice(this, joinPoint,(ConstructorCutSignaturePattern)adviceSignature);
break;
default:
toRun = new DefaultCcutAdvice(this, joinPoint,(ConstructorCutSignaturePattern)adviceSignature);
break;
}
toRun.execute();
}
public PointCutter equivalentSpecializer() {
initState();
if (getSpecializer() == null)
return ccutSpecializer;
else
return new ANDingPointCutter(ccutSpecializer,(PointCutter)getSpecializer());
}
/**
* Get advice method, i.e. <code>METHOD_ARGS(...)</code>. The advice
* method is used by the full code weaver.
*
* @return advice method
*/
public Method getMethod() {
return adviceSignature.methodObj;
}
public String toString() {
return " Crosscut: 'ConstructorCut' \n" +
" Advice:" + toStringSignature + "\n" +
" PointCutter: " + getSpecializer() + "\n";
}
}