KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ch > ethz > inf > iks > jvmai > jvmdi > AspectInterfaceImpl


1 // This file is part of the prose package.
2
//
3
// The contents of this file are subject to the Mozilla Public License
4
// Version 1.1 (the "License"); you may not use this file except in
5
// compliance with the License. You may obtain a copy of the License at
6
// http://www.mozilla.org/MPL//
7
// Software distributed under the License is distributed on an "AS IS" basis,
8
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
9
// for the specific language governing rights and limitations under the
10
// License.
11
//
12
// The Original Code is prose.
13
//
14
// The Initial Developer of the Original Code is Andrei Popovici. Portions
15
// created by Andrei Popovici are Copyright (C) 2002 Andrei Popovici.
16
// All Rights Reserved.
17
//
18
// Contributor(s):
19
// $Id: AspectInterfaceImpl.java,v 1.2 2004/05/12 09:41:54 anicoara Exp $
20
// =====================================================================
21
//
22
// (history at end)
23
//
24

25 package ch.ethz.inf.iks.jvmai.jvmdi;
26 import java.util.Map JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Iterator JavaDoc;
30
31 // used packages/classes
32
import java.lang.reflect.Field JavaDoc;
33 import java.lang.reflect.Method JavaDoc;
34 import java.lang.reflect.Modifier JavaDoc;
35
36 import java.net.URL JavaDoc;
37 import java.io.InputStream JavaDoc;
38 import java.io.IOException JavaDoc;
39
40 import ch.ethz.jvmai.JoinPointHook;
41 import ch.ethz.jvmai.JoinPoint;
42 import ch.ethz.jvmai.MethodEntryJoinPoint;
43 import ch.ethz.jvmai.MethodExitJoinPoint;
44 import ch.ethz.jvmai.FieldAccessJoinPoint;
45 import ch.ethz.jvmai.FieldModificationJoinPoint;
46 import ch.ethz.jvmai.ExceptionJoinPoint;
47 import ch.ethz.jvmai.ExceptionCatchJoinPoint;
48 import ch.ethz.jvmai.JVMAspectInterface;
49 import ch.ethz.jvmai.WatchAlreadySetException;
50 import ch.ethz.jvmai.WatchNotSetException;
51 import ch.ethz.jvmai.NotInitializedException;
52 import ch.ethz.jvmai.CannotSetWatchException;
53
54 import org.apache.bcel.generic.Instruction;
55 import org.apache.bcel.generic.InstructionHandle;
56 import org.apache.bcel.generic.InstructionList;
57 import org.apache.bcel.generic.ReturnInstruction;
58 import org.apache.bcel.classfile.ClassParser;
59 import org.apache.bcel.classfile.JavaClass;
60
61 /**
62  * <h3>About</h3>
63  * Interface AspectInterfaceImpl represents the aspect-interface to the jvmai-system.
64  * It's needed for initialization of the jvmai-system, management of joinpoint-watches and
65  * for enable or disable event-notification.
66  * <p>
67  * An instance of this interface can be obtained by calling the method
68  * <code>getAspectInterface()</code> of a jvmai-provider (class <code>DebuggerProvider</code>).
69  * <p>
70  * <h3>Implementation</h3>
71  * The implementation of this aspect interface is based on the debugger interface of the JVM.
72  * To receive notifications from the JVM, it uses the native code available in this class.
73  * <p>
74  *
75  * <h3>Bugs</h3>
76  * The JVMDI is not <em> consistent </em> over serveral J2SDK versions.
77  * <ul>
78  * <li> Startup ignores the openword/closed world assumption and the list of prefixes.
79  * <li> Under JDK 1.4.*, when throwing an exception within the notificaion, exception
80  * events are wrongly sent to the debugger
81  * <li> Under JDK 1.4.*, the 'GetThreadDepth' JVMDI function (name may be wrong),
82  * does not always work correclty. Consequently, the current implementation (as of prose 0.18.0)
83  * relies on the <em>height</em> of a frame relative to the frame which received
84  * the debugger notifcation.
85  * <li> Under JDK 1.4.*, the 'getBytecode' method exported by JVMDI works non-deterministically.
86  * (first time it works, subsequent times it generates illegal opcodes). The workaround
87  * uses BCEL and the class loader. However, this may incurr performance penalties.
88  * </ul>
89  *
90  * @version $Revision: 1.2 $
91  * @author Andrei Popovici
92  * @author Angela Nicoara
93  */

94 public
95 class AspectInterfaceImpl implements JVMAspectInterface
96 {
97  // load shared library upon class loading.
98
static
99     {
100       Class JavaDoc x=java.lang.RuntimeException JavaDoc.class;
101       try
102     {
103       // 1. assume we are an extension
104
System.loadLibrary("prosevm");
105     }
106       catch (java.lang.UnsatisfiedLinkError JavaDoc notInstalled)
107     {
108
109       // 2. no extension, we are in the development tree
110
try
111           {
112           System.load(System.getProperty("ch.ethz.inf.project.home") +
113               System.getProperty("file.separator","/") +
114               "lib" +
115               System.getProperty("file.separator","/") +
116               System.getProperty("os.arch") +
117               System.getProperty("file.separator","/") +
118               System.mapLibraryName("prosevm"));
119         }
120       catch (java.lang.UnsatisfiedLinkError JavaDoc notInProjectLib)
121         {
122         try
123             {
124             String JavaDoc path=System.getProperty("ch.ethz.inf.project.home") +
125                 System.getProperty("file.separator","/") +
126                 "site" +
127                 System.getProperty("file.separator","/") +
128                 "lib" +
129                 System.getProperty("file.separator","/") +
130                 System.getProperty("os.arch") +
131                 System.getProperty("file.separator","/") +
132                 System.mapLibraryName("prosevm");
133             System.load(path);
134             }
135         catch (java.lang.UnsatisfiedLinkError JavaDoc noProse)
136             {
137             throw new RuntimeException JavaDoc(noProse.toString());
138             }
139         }
140
141     }
142
143      }
144
145
146
147
148
149   Map JavaDoc fieldAccessMap;
150   Map JavaDoc fieldModificationMap;
151   Map JavaDoc methodExecutionMap;
152   Map JavaDoc exceptionThrowMap;
153   Map JavaDoc exceptionCatchMap;
154   JoinPointHook hook = null;
155   public boolean isInitialized = false; // FIXME; must be made not-public
156

157
158     static class CompoundAopTag
159     {
160     Object JavaDoc entryTag = null;
161     Object JavaDoc exitTag = null;
162     }
163
164   static ThreadLocal JavaDoc cflows = new ThreadLocal JavaDoc()
165     {
166       public Object JavaDoc initialValue()
167     {
168       synchronized(AspectInterfaceImpl.class)
169         {
170           return new ControlFlow();
171         }
172
173     }
174     };
175
176   private ControlFlow getCflow()
177     {
178       ControlFlow crtFlow = (ControlFlow)cflows.get();
179       if (crtFlow == null)
180     {
181       throw new Error JavaDoc("AspectInterface.getCflow: cflow should be always non-null\n");
182     }
183       return crtFlow;
184     }
185   private ClassLoader JavaDoc contingencyLoader = null;
186
187     /**
188      * Initializes the underlying jvmai system.
189      * <p>
190      * In addition, this method takes a list of java package-names and a
191      * boolean indicating how to interpret this prefixes. The prefixes are
192      * used by the jvmai system to determine the set of classes beeing
193      * relevant to the system at all.
194      * Depeding on the value of <code>openWorldAssumption</code>, prefixes
195      * are interpreted as followed:
196      * <p>
197      * <code>openWorldAssumption == true</code><br>
198      * The jvmai-system is instructed to treat ALL classes as relevant,
199      * EXCEPT the ones contained in a packages starting with one of the
200      * supplied prefixes in <code>packagePrefixes</code>
201      * <p>
202      * <code>openWorldAssumption == false</code><br>
203      * The jvmai-system is instructed to treat as relevant ONLY the classes
204      * contained in a packages starting with one of the supplied prefixes
205      * in <code>packagePrefixes</code>
206      *
207      * @param packagePrefixes List of prefixes for java package-names.
208      * @param openWorldAssumption Specifies how the prefixes are interpreted.
209      * @exception StartupException Use <code>StartupException.getMessage()</code> to get a detailed description
210      */

211     public synchronized void startup(String JavaDoc[] packagePrefixes, boolean openWorldAssumption)
212     {
213     // make sure all classes that are addressed during event notification are loaded already here
214
Class JavaDoc toload;
215     toload=ch.ethz.inf.iks.jvmai.jvmdi.AbsentInformationException.class;
216     toload=ch.ethz.inf.iks.jvmai.jvmdi.AspectInterfaceImpl.class;
217     toload=ch.ethz.inf.iks.jvmai.jvmdi.AspectInterfaceImpl.CompoundAopTag.class;
218     toload=ch.ethz.inf.iks.jvmai.jvmdi.CodeJoinPointImpl.class;
219     toload=ch.ethz.inf.iks.jvmai.jvmdi.CodeSignatureImpl.class;
220     toload=ch.ethz.inf.iks.jvmai.jvmdi.ControlFlow.class;
221     toload=ch.ethz.inf.iks.jvmai.jvmdi.DebuggerProvider.class;
222     toload=ch.ethz.inf.iks.jvmai.jvmdi.ExceptionJoinPointImpl.class;
223     toload=ch.ethz.inf.iks.jvmai.jvmdi.ExceptionCatchJoinPointImpl.class;
224     toload=ch.ethz.inf.iks.jvmai.jvmdi.FieldAccessJoinPointImpl.class;
225     toload=ch.ethz.inf.iks.jvmai.jvmdi.FieldJoinPointImpl.class;
226     toload=ch.ethz.inf.iks.jvmai.jvmdi.FieldModificationJoinPointImpl.class;
227     toload=ch.ethz.inf.iks.jvmai.jvmdi.FieldSignatureImpl.class;
228     toload=ch.ethz.inf.iks.jvmai.jvmdi.InvalidObjectException.class;
229     toload=ch.ethz.inf.iks.jvmai.jvmdi.InvalidVmStateException.class;
230     toload=ch.ethz.inf.iks.jvmai.jvmdi.ItemManipulationException.class;
231     toload=ch.ethz.inf.iks.jvmai.jvmdi.JoinPointContext.class;
232     toload=ch.ethz.inf.iks.jvmai.jvmdi.JoinPointLocation.class;
233     toload=ch.ethz.inf.iks.jvmai.jvmdi.MethodExecutionJoinPointImpl.class;
234     toload=ch.ethz.inf.iks.jvmai.jvmdi.ProseVmException.class;
235     toload=ch.ethz.inf.iks.jvmai.jvmdi.SignatureFormatException.class;
236     toload=ch.ethz.inf.iks.jvmai.jvmdi.StackFrameException.class;
237     toload=ch.ethz.inf.iks.jvmai.jvmdi.ThreadStateException.class;
238
239     toload=ch.ethz.jvmai.CannotSetWatchException.class;
240     toload=ch.ethz.jvmai.CatchClauseSignature.class;
241     toload=ch.ethz.jvmai.ClassSpecific.class;
242     toload=ch.ethz.jvmai.CodeJoinPoint.class;
243     toload=ch.ethz.jvmai.ExceptionJoinPoint.class;
244     toload=ch.ethz.jvmai.ExceptionCatchJoinPoint.class;
245     toload=ch.ethz.jvmai.FieldAccessJoinPoint.class;
246     toload=ch.ethz.jvmai.FieldJoinPoint.class;
247     toload=ch.ethz.jvmai.FieldModificationJoinPoint.class;
248     toload=ch.ethz.jvmai.FieldSignature.class;
249     toload=ch.ethz.jvmai.InvalidIdException.class;
250     toload=ch.ethz.jvmai.JVMAIException.class;
251     toload=ch.ethz.jvmai.JVMAIRuntimeException.class;
252     toload=ch.ethz.jvmai.JVMAspectInterface.class;
253     toload=ch.ethz.jvmai.JoinPoint.class;
254     toload=ch.ethz.jvmai.JoinPointHook.class;
255     toload=ch.ethz.jvmai.JoinPointStaticPart.class;
256     toload=ch.ethz.jvmai.MethodEntryJoinPoint.class;
257     toload=ch.ethz.jvmai.MethodExitJoinPoint.class;
258     toload=ch.ethz.jvmai.MethodSignature.class;
259     toload=ch.ethz.jvmai.NotInitializedException.class;
260     toload=ch.ethz.jvmai.Provider.class;
261     toload=ch.ethz.jvmai.Signature.class;
262     toload=ch.ethz.jvmai.StartupException.class;
263     toload=ch.ethz.jvmai.WatchAlreadySetException.class;
264     toload=ch.ethz.jvmai.WatchNotSetException.class;
265
266     Object JavaDoc crtClow=cflows.get();
267
268     methodExecutionMap = new HashMap JavaDoc();
269     fieldAccessMap = new HashMap JavaDoc();
270     fieldModificationMap = new HashMap JavaDoc();
271     exceptionThrowMap = new HashMap JavaDoc();
272     exceptionCatchMap = new HashMap JavaDoc();
273
274     if (contingencyLoader == null)
275         {
276         Iterator JavaDoc i = doGetClasses().iterator();
277         while(i.hasNext() && contingencyLoader == null)
278             {
279             Class JavaDoc cls=(Class JavaDoc)i.next();
280             contingencyLoader=cls.getClassLoader();
281             }
282         }
283
284
285     doStartup(packagePrefixes,openWorldAssumption);
286     isInitialized = true;
287     }
288
289
290     /**
291      * Sets a JoinPointHook as listener for jvmai-events.
292      * Whenever a watched joinpoint is reached or a class
293      * is loaded into the virtual machine, this JoinPointHook
294      * is notified by the aspect-interface. As long as no
295      * JoinPointHook is set (or after setting <code>null</code>),
296      * processing of joinpoint- and classload-events is disabled
297      * in the jvmai-system.
298      *
299      * @param hook JoinPointHook to set as listener.
300      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
301      */

302
303   public void setJoinPointHook(JoinPointHook hook)
304     {
305     if (!isInitialized)
306         {
307         throw new NotInitializedException("AspectInterfaceImpl.setJoinPointHook: JVMAI not initialized");
308         }
309       this.hook = hook;
310     }
311
312   public void teardown()
313     {
314       isInitialized=false;
315       fieldAccessMap = null;
316       fieldModificationMap = null;
317       methodExecutionMap = null;
318       exceptionThrowMap = null;
319       doTeardown();
320     }
321
322   private void setWatchPrecondition(Object JavaDoc arg, Object JavaDoc aopTag)
323     {
324       if (!isInitialized)
325     throw new NotInitializedException("JVMAspectInterface.setWatch: jvmai not initialized");
326       if (arg == null)
327     throw new NullPointerException JavaDoc("JVMAspectInterface.setWatch: null argument parameter");
328       if (aopTag == null)
329     throw new IllegalArgumentException JavaDoc("JVMAspectInterface.setWatch: null aopTag value");
330     }
331
332     /**
333      * Sets a watch on a field access joinpoint.
334      *
335      * @param cls Class declaring the field to be watched.
336      * @param fieldId Id of the field to be watched.
337      * @param aopTag A user-defined object saved with this watch.
338      * When the joinpoint is reached, this object is
339      * passed to the JoinPointHook as part of the
340      * JoinPoint-instance. This object may be <code>null</code>.
341      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
342      * @exception NullPointerException <code>cls</code> is <code>null</code>.
343      * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
344      * @exception CannotSetWatchException ?
345      * @exception WatchAlreadySetException There already exists a access-watch on the field.
346      */

347     public void setFieldAccessWatch(Field JavaDoc f, Object JavaDoc aopTag)
348     {
349     setWatchPrecondition(f,aopTag);
350     synchronized(fieldAccessMap)
351         {
352         try
353             {
354             doSetFieldAccessWatch(f.getDeclaringClass(),f,aopTag);
355             fieldAccessMap.put(f,aopTag);
356             }
357         catch (NullPointerException JavaDoc e)
358             { e.printStackTrace();}
359         }
360     }
361
362     /**
363      * Clears a watch on a field access joinpoint.
364      *
365      * @param cls Class declaring the field beeing watched.
366      * @param methodId Id of the field beeing watched. *
367      * @exception NotInitializedException Aspect-interface has not been intialized yet. Call <code>setup</code> first.
368      * @exception NullPointerException <code>cls</code> is <code>null</code>.
369      * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
370      * @exception WatchNotSetException There exists no access-watch on the field.
371      */

372     public void clearFieldAccessWatch(Field JavaDoc field)
373     {
374     if (!isInitialized)
375         throw new NotInitializedException("JVMAspectInterface.clearFieldAccessWatch: jvmai not initialized");
376     if (field == null)
377         throw new NullPointerException JavaDoc("JVMAspectInterface.clearFieldAccessWatch: null cls parameter");
378
379     synchronized(fieldAccessMap)
380       {
381         doClearFieldAccessWatch(field.getDeclaringClass(),field);
382         fieldAccessMap.remove(field);
383       }
384     }
385
386     /**
387      * Sets a watch on a field modification joinpoint.
388      *
389      * @param cls Class declaring the field to be watched.
390      * @param fieldId Id of the field to be watched.
391      * @param aopTag A user-defined object saved with this watch.
392      * When the joinpoint is reached, this object is
393      * passed to the JoinPointHook as part of the
394      * JoinPoint-instance. This object may be <code>null</code>.
395      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
396      * @exception NullPointerException <code>cls</code> is <code>null</code>.
397      * @exception InvalidIdException There exist no field with id <code>fieldId</code> in class <code>cls</code>.
398      * @exception CannotSetWatchException ?
399      * @exception WatchAlreadySetException There already exists a modification-watch on the field.
400      */

401     public void setFieldModificationWatch(Field JavaDoc field, Object JavaDoc aopTag)
402     {
403       setWatchPrecondition(field,aopTag);
404
405       synchronized(fieldModificationMap)
406         {
407         doSetFieldModificationWatch(field.getDeclaringClass(),field,aopTag);
408         fieldModificationMap.put(field,aopTag);
409         }
410     }
411
412     /**
413      * Clears a watch on a field modification joinpoint.
414      *
415      * @param cls Class declaring the field beeing watched.
416      * @param methodId Id of the field beeing watched.
417      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
418      * @exception NullPointerException <code>cls</code> is <code>null</code>.
419      * @exception InvalidIdException There exists no field with id <code>fieldId</code> in class <code>cls</code>.
420      * @exception WatchNotSetException There exists no modification-watch on the field.
421      */

422     public void clearFieldModificationWatch(Field JavaDoc field)
423     {
424
425     if (!isInitialized)
426         throw new NotInitializedException("JVMAspectInterface.clearFielddModificationWatch: jvmai not initialized");
427
428     synchronized(fieldModificationMap)
429         {
430         doClearFieldModificationWatch(field.getDeclaringClass(),field);
431         fieldModificationMap.remove(field);
432         }
433     }
434
435
436     // workaround for bug in 1.4.1. Subsequent invocations
437
// to 'getByteCode' deliveres *something else* than
438
// the original bytecode. As a consequence, we
439
// cache the end locations in a map, to avoid
440
// asking the vm twice to obtain the bytecodes for a method.
441
private HashMap JavaDoc endLocationsMap = new HashMap JavaDoc();
442
443
444     /// returns a list of Integer values with the bci of locations
445
private List JavaDoc returnLocations(Method JavaDoc m)
446     {
447
448     // use the cache, if possible
449
List JavaDoc endLocations = (List JavaDoc)endLocationsMap.get(m);
450     if (endLocations != null)
451         return endLocations;
452     else
453         endLocations= new java.util.Vector JavaDoc();
454
455
456     // obtain the bytecode for the method
457
InstructionList iList = null;
458     byte[] code = null;
459     try
460         {
461         code = doGetByteCode(m.getDeclaringClass(),m);
462         iList=new InstructionList(code);
463         }
464     catch (Exception JavaDoc e)
465         {
466         code = doGetByteCodeWithoutJvmdi(m);
467         iList= new InstructionList(code);
468         }
469
470     // search the bytecode for the method for 'return' bytecodes
471
InstructionHandle[] instructions = iList.getInstructionHandles();
472     for (int i=0; i < instructions.length; i++)
473         {
474         if (instructions[i].getInstruction() instanceof ReturnInstruction)
475             endLocations.add(new Integer JavaDoc(instructions[i].getPosition()));
476         }
477
478     // treat special case of empty methods
479
if ( (code.length == 1 || code.length == 0) && (!endLocations.contains(new Integer JavaDoc(0))))
480         {
481         endLocations.add(new Integer JavaDoc(0));
482         }
483     endLocationsMap.put(m,endLocations);
484     return endLocations;
485     }
486
487
488
489     private byte[] doGetByteCodeWithoutJvmdi (Method JavaDoc m)
490     {
491     ClassLoader JavaDoc cl;
492
493     cl= m.getDeclaringClass().getClassLoader();
494     if (cl == null)
495         cl = contingencyLoader;
496
497     String JavaDoc fileName = m.getDeclaringClass().getName().replace('.','/') + ".class";
498     URL JavaDoc resource = cl.getResource(fileName);
499     InputStream JavaDoc classStream = cl.getResourceAsStream(fileName);
500     try
501         {
502 // InputStream classStream = resource.openStream();
503
ClassParser cparser=new ClassParser(classStream,fileName);
504         JavaClass parsedClass = cparser.parse();
505         org.apache.bcel.classfile.Method[] methods = parsedClass.getMethods();
506         org.apache.bcel.classfile.Method javaMethod = null;
507         for (int i = 0; i < methods.length && javaMethod == null; i++)
508             {
509             if (methods[i].getName().equals(m.getName()) &&
510                 JNIUtil.jniSignature(m).equals(methods[i].getSignature()))
511                 {
512                 javaMethod=methods[i];
513                 }
514             }
515         classStream.close();
516
517         if (javaMethod != null)
518             {
519             return javaMethod.getCode().getCode();
520             }
521         else
522             {
523             throw new Error JavaDoc("could not find method in code");
524             }
525
526         }
527     catch (IOException JavaDoc cannotAccessClassCode)
528         {
529         throw new RuntimeException JavaDoc(cannotAccessClassCode.toString());
530         }
531     }
532
533
534     /**
535      * Sets a watch on a method entry joinpoint.
536      *
537      * @param cls Class declaring the method to be watched.
538      * @param methodId Id of the method to be watched.
539      * @param aopTag A user-defined object saved with this watch.
540      * When the joinpoint is reached, this object is
541      * passed to the JoinPointHook as part of the
542      * JoinPoint-instance. This object may be <code>null</code>.
543      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
544      * @exception NullPointerException <code>cls</code> is <code>null</code>.
545      * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
546      * @exception CannotSetWatchException The method must not be abstract or native.
547      * @exception WatchAlreadySetException There already exists a entry-watch on the method.
548      */

549     public synchronized void setMethodEntryWatch(Method JavaDoc m, Object JavaDoc aopTag)
550     {
551     // preconditions
552
setWatchPrecondition(m,aopTag);
553         if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
554         throw new CannotSetWatchException("JVMAspectInterface.setMethodEntryWatch: cannot set watches on interfaces");
555
556     // 1. build the aop tag (if not existent); check, if existent the invariant
557
CompoundAopTag executionTag = (CompoundAopTag)methodExecutionMap.get(m);
558
559
560     if (executionTag == null)
561         executionTag = new CompoundAopTag();
562     if (executionTag.entryTag != null)
563         throw new WatchAlreadySetException("JVMAspectInterface.setMethodEntryWatch:" + m);
564     else
565         executionTag.entryTag=aopTag;
566
567     // if the exit tag is set and 'bci=0' is an end location, we use the
568
// execution tag; otherwise we use our own tag
569
CompoundAopTag tagToBeSet;
570     boolean tagIsCommonToEntryExit = false;
571     if (returnLocations(m).contains(new Integer JavaDoc(0)))
572         {
573         tagToBeSet=executionTag;
574         tagIsCommonToEntryExit = true;
575         }
576     else
577         {
578         tagToBeSet=new CompoundAopTag();
579         tagToBeSet.entryTag=aopTag;
580         tagToBeSet.exitTag=null;
581         tagIsCommonToEntryExit = false;
582         }
583
584     // 2. activate the location watch
585
try
586         {
587         doSetLocationWatch(m.getDeclaringClass(),m,0,tagToBeSet);
588
589         }
590     catch (WatchAlreadySetException e)
591         {
592         if (!(tagIsCommonToEntryExit && executionTag.exitTag!=null))
593             throw new Error JavaDoc("JVMAspectInteface.setMethodEntryWatch:" +
594                     "JMD reports watch already set, but the exit tag is null");
595         }
596     methodExecutionMap.put(m,executionTag);
597
598     }
599
600     /**
601      * Clears a watch on a method entry joinpoint.
602      *
603      * @param cls Class declaring the method beeing watched.
604      * @param methodId Id of the method beeing watched.
605      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
606      * @exception NullPointerException <code>cls</code> is <code>null</code>.
607      * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
608      * @exception WatchNotSetException There exists no entry-watch on the method.
609      */

610     public synchronized void clearMethodEntryWatch(Method JavaDoc m)
611     {
612
613     // preconditions
614
if (!isInitialized)
615         throw new NotInitializedException("JVMAspectInterface.clearMethodEntryWatch: jvmai not initialized");
616     if (m == null)
617         throw new NullPointerException JavaDoc("JVMAspectInterface.clearMethodEntryWatch: null m parameter");
618     if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
619         throw new CannotSetWatchException("JVMAspectInterface.setMethodEntryWatch: cannot clear watches on interfaces");
620
621     // 1. first check whether we have anything to delete
622
CompoundAopTag oldTag = (CompoundAopTag) methodExecutionMap.get(m);
623     if (oldTag == null)
624         {
625         throw new WatchNotSetException("JVMAspectInterface.clearMethodEntryWatch");
626         }
627
628     // 2. then we delete the aopTag
629
if (oldTag.entryTag == null)
630         throw new WatchNotSetException("JVMAspectInterface.clearMethodEntryWatch:" + m);
631     else
632         oldTag.entryTag = null;
633
634     // 3. we actually remove the watch if
635
// - no method exit tag is set OR
636
// - '0' is not an end location
637
if (oldTag.exitTag == null || (!returnLocations(m).contains(new Integer JavaDoc(0))) )
638         {
639         doClearLocationWatch(m.getDeclaringClass(),m,0);
640         }
641
642     // 4. clear the tag map, if noboy is interested in this method
643
if (oldTag.exitTag == null)
644         methodExecutionMap.remove(m);
645
646     }
647
648
649     // remove the map only if there are no breakpoints left in the exits;
650
/**
651      * Sets a watch on a method exit joinpoint.
652      *
653      * @param cls Class declaring the method to be watched.
654      * @param methodId Id of the method to be watched.
655      * @param aopTag A user-defined object saved with this watch.
656      * When the joinpoint is reached, this object is
657      * passed to the JoinPointHook as part of the
658      * JoinPoint-instance. This object may be <code>null</code>.
659      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
660      * @exception NullPointerException <code>cls</code> is <code>null</code>.
661      * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
662      * @exception CannotSetWatchException The method must not be abstract or native.
663      * @exception WatchAlreadySetException There already exists a exit-watch on the method.
664      */

665     public synchronized void setMethodExitWatch(Method JavaDoc m, Object JavaDoc aopTag)
666     {
667     // preconditions
668
setWatchPrecondition(m,aopTag);
669     if ((m.getModifiers() & (Modifier.ABSTRACT | Modifier.NATIVE)) != 0)
670         throw new CannotSetWatchException("JVMAspectInterface.setMethodExitWatch: cannot set watches on interfaces");
671
672     // 1. check whether it is already set, and then set the tag
673
CompoundAopTag compoundTag = (CompoundAopTag)methodExecutionMap.get(m);
674     if (compoundTag == null)
675         {
676         compoundTag = new CompoundAopTag();
677         methodExecutionMap.put(m,compoundTag);
678         }
679
680     if (compoundTag.exitTag != null)
681         throw new WatchAlreadySetException("JVMAspectInteface.setMethodExitWatch" + m);
682     compoundTag.exitTag = aopTag;
683
684     // 2. find out the end locations of this method (everywhere were 'return' exists + '0' if
685
// the method is empty
686

687     List JavaDoc endLocations = returnLocations(m);
688
689     // 3. iterate over locations and set the watch
690
Iterator JavaDoc j = endLocations.iterator();
691     while (j.hasNext())
692         {
693
694         CompoundAopTag tagToBeSet;
695         int bci = ((Integer JavaDoc)(j.next())).intValue();
696
697
698         if (bci == 0)
699             {
700             // if this return location is ALSO an entry location, we use a (X,Y) compound tag
701
tagToBeSet=compoundTag;
702             }
703         else
704             {
705             // if this return location is NOT an entry location, we use a (null,Y) compound tag
706
tagToBeSet=new CompoundAopTag();
707             tagToBeSet.entryTag=null;
708             tagToBeSet.exitTag=aopTag;
709             }
710
711
712         try
713             {
714             doSetLocationWatch(m.getDeclaringClass(),m,bci,tagToBeSet);
715             }
716         catch (WatchAlreadySetException entryWatchOnZeroLengthMethod)
717             {
718             // this exception is ok only if the return location is a entry location, too,
719
// and the entry location is already set.
720
if (compoundTag.entryTag != null && bci == 0)
721                 {}// everyhting is fine
722
else
723                 {
724                 // this is an error, it should have been caputred earlier
725
Error JavaDoc x =new Error JavaDoc("JVMAspectInterface.setMethodEntryWatch: " +
726                            " watch set on exit in spite of non-zero length method:" + m);
727                 x.printStackTrace();
728                 throw x;
729                 }
730             }
731         }
732     }
733
734     /**
735      * Clears a watch on a method exit joinpoint.
736      *
737      * @param cls Class declaring the method beeing watched.
738      * @param methodId Id of the method beeing watched.
739      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
740      * @exception NullPointerException <code>cls</code> is <code>null</code>.
741      * @exception InvalidIdException There exists no method with id <code>methodId</code> in class <code>cls</code>.
742      * @exception WatchNotSetException There exists no exit-watch on the method.
743      */

744     public synchronized void clearMethodExitWatch(Method JavaDoc m)
745     {
746     // preconditions
747
if (!isInitialized)
748         throw new NotInitializedException("JVMAspectInterface.clearMethodExitWatch: jvmai not initialized");
749     if (m == null)
750         throw new NullPointerException JavaDoc("JVMAspectInterface.clearMethodExitWatch: null Method parameter");
751         if (m.getDeclaringClass().isInterface())
752         throw new WatchNotSetException("JVMAspectInterface.clearMethodExitWatch: cannot clear watches on interfaces");
753
754     // 1. obtain the tag to delete
755
CompoundAopTag compoundTag = (CompoundAopTag)methodExecutionMap.get(m);
756
757     if (compoundTag == null || compoundTag.exitTag == null)
758         {
759         throw new WatchNotSetException("JVMAspectInterface.clearMethodExitWatch: " + m);
760         }
761     compoundTag.exitTag = null;
762
763     // 2. iterate over the 'return' locations and delete the watches
764

765     Iterator JavaDoc j = returnLocations(m).iterator();
766
767
768     while (j.hasNext())
769         {
770         int bci = ((Integer JavaDoc)(j.next())).intValue();
771         if (bci != 0 || (compoundTag.entryTag == null))
772             {
773             doClearLocationWatch(m.getDeclaringClass(),m,bci);
774             }
775         }
776
777     // 3. if nobody is interested in this method, delete the compound tag, too
778
if (compoundTag.entryTag == null)
779         methodExecutionMap.remove(m);
780     }
781
782     /**
783      * Sets a watch on a exception throw joinpoint.
784      *
785      * @param cls Exception Class that should be watched.
786      * @param aopTag A user-defined object saved with this watch.
787      * When the joinpoint is reached, this object is
788      * passed to the JoinPointHook as part of the
789      * JoinPoint-instance. This object may be <code>null</code>.
790      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
791      * @exception NullPointerException <code>cls</code> is <code>null</code>.
792      * @exception WatchAlreadySetException There already exists a exceptionThrow-watch at this point.
793      */

794     public void setExceptionThrowWatch(Class JavaDoc cls, Object JavaDoc aopTag)
795     {
796     setWatchPrecondition(cls,aopTag);
797
798     synchronized(exceptionThrowMap)
799         {
800         doSetExceptionWatch(cls,aopTag);
801         exceptionThrowMap.put(cls, aopTag);
802         }
803
804     }
805
806     /**
807      * Clears a watch on a exception throw joinpoint.
808      *
809      * @param cls Exception Class that should be watched.
810      * @param methodId Id of the method in which the watched Exception is thrown.
811      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
812      * @exception NullPointerException <code>cls</code> is <code>null</code>.
813      * @exception WatchNotSetException There exists no exceptionThrow-watch at this point.
814      */

815     public void clearExceptionThrowWatch(Class JavaDoc cls)
816     {
817
818     if (!isInitialized)
819         throw new NotInitializedException("JVMAspectInterface.clearExceptionThrowWatch: jvmai not initialized");
820     if (cls == null)
821         throw new NullPointerException JavaDoc("JVMAspectInterface.clearExceptionThrowWatch: null cls parameter");
822
823     synchronized(exceptionThrowMap)
824     {
825         doClearExceptionWatch(cls);
826         if (exceptionThrowMap.containsKey(cls))
827             exceptionThrowMap.remove(cls);
828         else
829             throw new WatchNotSetException();
830     }
831
832     }
833
834
835     /**
836      * Sets a watch on a exception catch joinpoint.
837      *
838      * @param cls Exception Class that should be watched.
839      * @param aopTag A user-defined object saved with this watch.
840      * When the joinpoint is reached, this object is
841      * passed to the JoinPointHook as part of the
842      * JoinPoint-instance. This object may be <code>null</code>.
843      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
844      * @exception NullPointerException <code>cls</code> is <code>null</code>.
845      * @exception WatchAlreadySetException There already exists a exceptionCatch-watch at this point.
846      */

847     public void setExceptionCatchWatch(Class JavaDoc cls, Object JavaDoc aopTag) {
848         setWatchPrecondition(cls,aopTag);
849
850         synchronized(exceptionCatchMap) {
851             doSetExceptionCatchWatch(cls,aopTag);
852             exceptionCatchMap.put(cls, aopTag);
853         }
854     }
855
856     /**
857      * Clears a watch on a exception catch joinpoint.
858      *
859      * @param cls Exception Class that should be watched.
860      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
861      * @exception NullPointerException <code>cls</code> is <code>null</code>.
862      * @exception WatchNotSetException There exists no exceptionCatch-watch at this point.
863      */

864     public void clearExceptionCatchWatch(Class JavaDoc cls) {
865
866         if (!isInitialized)
867             throw new NotInitializedException("JVMAspectInterface.clearExceptionCatchWatch: jvmai not initialized");
868         if (cls == null)
869             throw new NullPointerException JavaDoc("JVMAspectInterface.clearExceptionCatchWatch: null cls parameter");
870     
871         synchronized(exceptionCatchMap) {
872            doClearExceptionCatchWatch(cls);
873             if (exceptionCatchMap.containsKey(cls))
874                 exceptionCatchMap.remove(cls);
875             else
876                 throw new WatchNotSetException();
877         }
878     }
879
880
881     /**
882      * Suspend notification regarding the specified thread.
883      * Successive calls to <code>suspendNotification</code>
884      * have to be balanced by (at least) the same number of calls to
885      * <code>resumeNotification</code>, or the jvmai-system
886      * will not resume notification.
887      *
888      * @param thread Thread for which to disable notification.
889      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
890      * @exception NullPointerException <code>thread</code> is <code>null</code>.
891      */

892     public void suspendNotification(Thread JavaDoc thread)
893     {
894     if (!isInitialized)
895         throw new NotInitializedException("JVMAspectInterface.resumeNotification: jvmai not initialized");
896
897     doSuspendNotification(thread);
898     }
899
900     /**
901      * Resumes notification regarding the specified thread.
902      * Successive calls to <code>resumeNotification</code>
903      * without preceding calls to <code>suspendNotification</code>
904      * will be ignored by the jvmai-system.
905      *
906      * @param thread Thread for which to reenable notification.
907      * @exception NotInitializedException Aspect-interface has not been initialized yet. Call <code>setup</code> first.
908      * @exception NullPointerException <code>thread</code> is <code>null</code>.
909      */

910     public void resumeNotification(Thread JavaDoc thread)
911     {
912     if (!isInitialized)
913         throw new NotInitializedException("JVMAspectInterface.resumeNotification: jvmai not initialized");
914     doResumeNotification(thread);
915     }
916
917     public List JavaDoc getLoadedClasses()
918     {
919     return doGetClasses();
920     }
921
922     private void doOnClassLoad(Class JavaDoc cls)
923     {
924
925     if (hook==null)
926         return;
927
928     hook.onClassLoad(cls);
929     }
930
931     private void doOnMethodExecution(MethodExecutionJoinPointImpl jp)
932     {
933     // find out whether it is entry, exit, or both
934
if (hook==null)
935         return;
936
937
938     Method JavaDoc method = jp.getMethod();
939     CompoundAopTag compoundTag = (CompoundAopTag)jp.getAopTag();
940
941     if (compoundTag.entryTag!=null)
942         {
943         jp.aopTag = compoundTag.entryTag;
944         jp.setKind(true);
945         hook.onMethodEntry(jp);
946         }
947     if (compoundTag.exitTag != null)
948         {
949         jp.aopTag = compoundTag.exitTag;
950         jp.setKind(false);
951         hook.onMethodExit(jp);
952         }
953     }
954
955     private void doOnFieldAccess(FieldAccessJoinPointImpl jp)
956     {
957     if (hook==null)
958         return;
959     hook.onFieldAccess(jp);
960     }
961
962     private void doOnFieldModification(FieldModificationJoinPointImpl jp)
963     {
964     if (hook==null)
965         return;
966
967     hook.onFieldModification(jp);
968     }
969
970     private void doOnExceptionThrow(ExceptionJoinPointImpl jp)
971     {
972     if (hook==null)
973         return;
974
975     hook.onExceptionThrow(jp);
976     }
977     
978     private void doOnExceptionCatch(ExceptionCatchJoinPointImpl jp) {
979         try
980         {
981         //System.err.println("Executing do on exception catch "); //angy test
982
if (hook==null)
983             return;
984     
985         hook.onExceptionCatch(jp);
986         } catch (Throwable JavaDoc x)
987         {
988             System.err.println("BBBBB");
989         }
990     }
991     
992
993
994     private native void doStartup(Object JavaDoc[] prefixes, boolean openWorld);
995     private native void doTeardown();
996     private native void doSetLocationWatch(Class JavaDoc c, Method JavaDoc m, int bci,Object JavaDoc tag);
997     private native void doClearLocationWatch(Class JavaDoc c, Method JavaDoc m, int bci);
998     private native void doSetFieldAccessWatch(Class JavaDoc c, Field JavaDoc f,Object JavaDoc tag);
999     private native void doClearFieldAccessWatch(Class JavaDoc c, Field JavaDoc f);
1000    private native void doSetFieldModificationWatch(Class JavaDoc c, Field JavaDoc f, Object JavaDoc tag);
1001    private native void doClearFieldModificationWatch(Class JavaDoc c, Field JavaDoc f);
1002    private native void doSetExceptionWatch(Class JavaDoc throwableClass, Object JavaDoc tag);
1003    private native void doClearExceptionWatch(Class JavaDoc trowableClass);
1004    private native void doSetExceptionCatchWatch(Class JavaDoc throwableClass, Object JavaDoc tag);
1005    private native void doClearExceptionCatchWatch(Class JavaDoc trowableClass);
1006    private native byte [] doGetByteCode(Class JavaDoc c, Method JavaDoc m);
1007    private native List JavaDoc doGetClasses();
1008    private native void doSuspendNotification(Thread JavaDoc t);
1009    private native void doResumeNotification(Thread JavaDoc t);
1010}
1011
1012//======================================================================
1013
//
1014
// $Log: AspectInterfaceImpl.java,v $
1015
// Revision 1.2 2004/05/12 09:41:54 anicoara
1016
// Remove the README.RVM file
1017
//
1018
// Revision 1.1.1.1 2003/07/02 15:30:49 apopovic
1019
// Imported from ETH Zurich
1020
//
1021
// Revision 1.7 2003/07/02 12:42:44 anicoara
1022
// Added CatchJoinPoint Functionality (Requests, Join-Points, Filters, CatchCuts, Tests)
1023
//
1024
// Revision 1.6 2003/05/06 15:08:21 popovici
1025
// Input stream now directly from class-loader, not from URL (addressing a problem of midas)
1026
//
1027
// Revision 1.5 2003/05/05 17:46:22 popovici
1028
// Refactorization step (runes->prose) cleanup
1029
//
1030
// Revision 1.4 2003/04/30 14:44:19 popovici
1031
// potential bug fix: after teardown, the state of the maps (e.g., fieldAccessMap) was kept; fixed
1032
//
1033
// Revision 1.3 2003/04/17 08:47:02 popovici
1034
// Important functionality additions
1035
// - Cflow specializers
1036
// - Restructuring of the MethodCut, SetCut, ExceptionCut, and GetCut (they are much smaller)
1037
// - Transactional capabilities
1038
// - Total refactoring of Specializer evaluation, which permits fine-grained distinction
1039
// between static and dynamic specializers.
1040
// - Functionality pulled up in abstract classes
1041
// - Uniformization of advice methods patterns and names
1042
//
1043
// Revision 1.2 2003/03/04 16:09:31 popovici
1044
// Documentation improvements
1045
//
1046
// Revision 1.1 2003/03/04 11:26:19 popovici
1047
// Important refactorization step (march):
1048
// - removal of 'JoinPointEvents'; JoinPoints now have the same function as events
1049
// - reimplementation of the JVMAIDebuggerAspectInterface (better performance, coding conventions, removal of ProseVM
1050
// structures
1051
//
1052
// Revision 1.8 2002/11/27 17:09:43 popovici
1053
// Minor chages; Teardown no sets isTeardown to false
1054
//
1055
// Revision 1.7 2002/10/17 12:23:38 pschoch
1056
// Added throw capabability to JVMAI
1057
//
1058
// Revision 1.6 2002/09/21 14:04:31 popovici
1059
// Bug 0000010 fixed. Added 'teardown' procedure
1060
// in the JVMAI, Jikes & JDK prose implementation
1061
//
1062
// Revision 1.5 2002/03/28 13:48:11 popovici
1063
// Mozilla-ified
1064
//
1065
// Revision 1.4 2002/02/18 15:09:59 popovici
1066
// Typo in DebuggerAspectInterface corrected
1067
//
1068
// Revision 1.3 2002/02/18 14:38:43 popovici
1069
// - Class comments added for DebuggerAspectInterface, ProseVM, ProseJPM and DebuggerInfoInterface
1070
// - Bug fix in ProseVM that appeared when the boot classes where a VM extnesion
1071
// - minor changes (edits) in prosevm.c
1072
//
1073
// Revision 1.2 2002/02/14 16:02:23 popovici
1074
// Bug fixes, PROSEVM moved to boot
1075
//
1076
// Revision 1.1 2002/02/06 11:53:46 popovici
1077
// Refactoring from prose classical to jvmai
1078
//
1079
// Revision 1.2 2002/01/24 12:59:38 smarkwal
1080
// Comments added.
1081
//
1082
// Revision 1.1 2001/12/14 15:01:17 smarkwal
1083
// Initial Revision
1084
//
1085
Popular Tags