001: //
002: // This file is part of the prose package.
003: //
004: // The contents of this file are subject to the Mozilla Public License
005: // Version 1.1 (the "License"); you may not use this file except in
006: // compliance with the License. You may obtain a copy of the License at
007: // http://www.mozilla.org/MPL/
008: //
009: // Software distributed under the License is distributed on an "AS IS" basis,
010: // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: // for the specific language governing rights and limitations under the
012: // License.
013: //
014: // The Original Code is prose.
015: //
016: // The Initial Developer of the Original Code is Andrei Popovici. Portions
017: // created by Andrei Popovici are Copyright (C) 2002 Andrei Popovici.
018: // All Rights Reserved.
019: //
020: // Contributor(s):
021: // $Id: SignaturePattern.java,v 1.2 2003/07/11 12:27:43 apopovic Exp $
022: // =====================================================================
023: //
024: // (history at end)
025: //
026:
027: package ch.ethz.prose.crosscut;
028:
029: // used packages
030: import java.lang.reflect.Method;
031: import java.lang.Class;
032:
033: /** Every Crosscut contains a method to be executed when a join-point is hit.
034: * In the case of <code>MethodCut</code> objects, the SignaturePattern has three
035: * roles:
036: * <ul>
037: * <li> The pattern role: through a special signature, define matches for the
038: * target class, and for the parameters of the methods belonging to the target.
039: *
040: * <li> The method finder role: determine which method o of the crosscut
041: * must be ivoked upon a hit join-point.
042: *
043: * <li> The optimization role: to cathegorize the signature of the advice
044: * method, such that the subsequent execution of the advice method is efficient.
045: * The categorization is currently performed according to the <code>SIGNATURE__XXX</code>
046: * constants.
047: * </ul>
048: *
049: * @version $Revision: 1.2 $
050: * @author Andrei Popovici
051: */
052: public abstract class SignaturePattern {
053:
054: // work constants bit 3 bit 2
055: protected final static int WILDCARD_1 = 0x02;
056: protected final static int WILDCARD_2 = 0x04;
057: protected final static int CONCRETE_1 = 0x08;
058: protected final static int CONCRETE_2 = 0x01;
059:
060: /// constants reflecting the cathegory of the signature of <code>methodObj</code>
061: protected static final int SIGNATURE__WILDCARD__WILDCARD = WILDCARD_1
062: | WILDCARD_2;
063: protected static final int SIGNATURE__WILDCARD__CONCRETE = WILDCARD_1
064: | CONCRETE_2;
065: protected static final int SIGNATURE__CONCRETE__WILDCARD = CONCRETE_1
066: | WILDCARD_2;
067: protected static final int SIGNATURE__CONCRETE__CONCRETE = CONCRETE_1
068: | CONCRETE_2;
069: protected static final int SIGNATURE__ARBITRARY = 0;
070: protected static final int SIGNATURE__EMPTY = 0x1000;
071:
072: /** The signature cathegory of <code>methodObj</code>.
073: */
074: protected int signatureCathegory = SIGNATURE__ARBITRARY;
075:
076: /** The method to be invoked upon reaching a joinpoint,
077: * or <code>null</code> if the enclosing
078: * Crosscut defines its own <code>adviceMethod</code>.
079: */
080: protected transient Method methodObj = null;
081:
082: /** The signature of <code>methodObj</code>, equivalent to
083: * <code>methodObj.getParameterTypes()</code>. Present
084: * for efficiency reasons.
085: */
086: protected transient Class[] signature = null;
087:
088: protected transient Class wildcardClass = null;
089:
090: /**
091: * Return the number of arguments required by this advice.
092: */
093: protected int getLength() {
094: return signature.length;
095: }
096:
097: protected Class getReceiverType() {
098: if (signature.length == 0)
099: return null;
100: else
101: return signature[0];
102: }
103:
104: /** When no advice action is set, it returns true.
105: * If an advice action exists, it returns true
106: * if the pattern-matching signature acepts <code>actualClass</code>
107: * as a potential crosscut class.
108: *
109: */
110: protected boolean matchesTarget(Class actualClass) {
111: if (signatureCathegory == SIGNATURE__EMPTY)
112: return true;
113: else
114: return isAssignable(actualClass, signature[0]);
115: }
116:
117: protected boolean isAssignable(Class actualParameterType,
118: Class formalParameterType) throws Error {
119: if (Wildcard.class.isAssignableFrom(formalParameterType)) {
120: try {
121: if (((Wildcard) formalParameterType.newInstance())
122: .isAssignableFrom(actualParameterType))
123: return true;
124:
125: // the Wilcard specification states that wildcard classes
126: // should have an emtpy default constructor. If they
127: // don't have: it is a RUNES IMPLEMENTATION ERROR
128: } catch (IllegalAccessException noConstructor) {
129: throw new Error(noConstructor.toString());
130: } catch (InstantiationException wrongConstructor) {
131: throw new Error(wrongConstructor.toString());
132: }
133: return false;
134: } else if (formalParameterType
135: .isAssignableFrom(actualParameterType))
136: return true;
137: else
138: return false;
139: }
140:
141: protected void initFromMethod(Class methodClass, String adviceName,
142: Class wildcardClass, Class htop) {
143:
144: this .wildcardClass = wildcardClass;
145: initAdviceMethod(methodClass, adviceName, htop);
146: signature = methodObj.getParameterTypes();
147: initSignatureCathegory();
148: }
149:
150: private void initAdviceMethod(Class methodClass, String adviceName,
151: Class hierarchyTop) {
152: int ambigousCnt = 0;
153: Method mObj = null;
154: Class crtClass = methodClass;
155:
156: // look up a method with the name 'adviceName'; if such a method is found,
157: while (crtClass != null && !crtClass.equals(hierarchyTop) && // (e.g., crtClass != MethodCut)
158: hierarchyTop.isAssignableFrom(crtClass) && // (e.g., crtClass subclass of MethodCut)
159: mObj == null) {
160: Method[] methods = crtClass.getDeclaredMethods();
161: ambigousCnt = 0;
162:
163: // we have to select some method
164: // try to match a method with such a name
165:
166: for (int i = 0; i < methods.length; i++)
167: if (methods[i].getName().equals(adviceName)) {
168: mObj = methods[i];
169: ambigousCnt++;
170: }
171:
172: crtClass = crtClass.getSuperclass();
173: }
174:
175: if (mObj == null)
176: throw new MissingInformationException(
177: "No advice action specified");
178: if (ambigousCnt > 1)
179: throw new MissingInformationException(
180: "Two advice methods detected. Ambigous advice specification");
181:
182: try {
183: mObj.setAccessible(true);
184: } catch (SecurityException opaqueCrosscut) {
185: // this is not very likely to ocurr
186: }
187:
188: methodObj = mObj;
189: }
190:
191: private void initSignatureCathegory() {
192: Method m = methodObj;
193: int optimization = SIGNATURE__ARBITRARY;
194: Class[] adviceParamTypes = m.getParameterTypes();
195:
196: if (adviceParamTypes.length == 0) {
197: signatureCathegory = SIGNATURE__EMPTY;
198: return;
199: }
200:
201: // figure out whether the receiver is a wildcard
202: if (ANY.class.isAssignableFrom(adviceParamTypes[0]))
203: optimization |= WILDCARD_1;
204: else
205: optimization |= CONCRETE_1;
206:
207: // figure out whether *all* parameters are wildcard
208: boolean restIsWildcard = true;
209: boolean restIsConcrete = true;
210: for (int i = 1; i < adviceParamTypes.length; i++) {
211: if (Wildcard.class.isAssignableFrom(adviceParamTypes[i]))
212: restIsConcrete = false;
213: else
214: restIsWildcard = false;
215: }
216:
217: // and update the result
218: if (restIsWildcard && adviceParamTypes.length == 2
219: && adviceParamTypes[1].equals(wildcardClass))
220: optimization |= WILDCARD_2;
221: if (restIsConcrete)
222: optimization |= CONCRETE_2;
223:
224: signatureCathegory = optimization;
225: }
226:
227: protected boolean isAssignable(Class[] actualParameterType,
228: Class formalParameterType) {
229: if (Wildcard.class.isAssignableFrom(formalParameterType)) {
230: try {
231: if (((Wildcard) formalParameterType.newInstance())
232: .isAssignableFrom(actualParameterType))
233: return true;
234: } catch (IllegalAccessException noConstructor) {
235: throw new Error(noConstructor.toString());
236: } catch (InstantiationException wrongConstructor) {
237: throw new Error(wrongConstructor.toString());
238: }
239: return false;
240: } else
241: return false;
242: }
243:
244: }
245:
246: //======================================================================
247: //
248: // $Log: SignaturePattern.java,v $
249: // Revision 1.2 2003/07/11 12:27:43 apopovic
250: // Bug fix for rare cases. Some classed loaded late may throw a 'NoClassDefError' when
251: // trying to retrieve the declared methods; The crosscut for such cases is now an empty listt
252: //
253: // Revision 1.1.1.1 2003/07/02 15:30:51 apopovic
254: // Imported from ETH Zurich
255: //
256: // Revision 1.2 2003/05/06 15:51:31 popovici
257: // Mozilla-ification
258: //
259: // Revision 1.1 2003/05/05 13:58:14 popovici
260: // renaming from runes to prose
261: //
262: // Revision 1.1 2003/04/17 12:49:23 popovici
263: // Refactoring of the crosscut package
264: // ExceptionCut renamed to ThrowCut
265: // McutSignature is now SignaturePattern
266: //
267: // Revision 1.2 2003/04/17 08:47:20 popovici
268: // Important functionality additions
269: // - Cflow specializers
270: // - Restructuring of the MethodCut, SetCut, ThrowCut, and GetCut (they are much smaller)
271: // - Transactional capabilities
272: // - Total refactoring of Specializer evaluation, which permits fine-grained distinction
273: // between static and dynamic specializers.
274: // - Functionality pulled up in abstract classes
275: // - Uniformization of advice methods patterns and names
276: //
277: // Revision 1.1 2003/03/05 15:26:41 popovici
278: // Bug fixes after the extraction of 'AdviceMethod' and 'AdviceExcecution' as top level classes:
279: // - a new Abstract class is superclassing 'UserDefinedAdvice' and 'DefaultAdvice'
280: //
|