KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > ch > ethz > prose > LocalAspectManager


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

27 package ch.ethz.prose;
28
29 // used packages
30
import java.security.AccessControlException JavaDoc;
31 import java.util.Collections JavaDoc;
32 import java.util.Comparator JavaDoc;
33 import java.util.HashSet JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.List JavaDoc;
36 import java.util.Set JavaDoc;
37 import java.util.SortedSet JavaDoc;
38 import java.util.TreeSet JavaDoc;
39 import java.util.Vector JavaDoc;
40 import java.util.HashMap JavaDoc;
41
42 import ch.ethz.jvmai.JVMAspectInterface;
43 import ch.ethz.prose.crosscut.Crosscut;
44 import ch.ethz.prose.crosscut.CrosscutRequest;
45 import ch.ethz.prose.crosscut.CrosscutGroup;
46 import ch.ethz.prose.engine.ClassLoadListener;
47 import ch.ethz.prose.engine.JoinPointManager;
48 import ch.ethz.prose.engine.JoinPointRequest;
49 import ch.ethz.prose.query.JoinPointRequestSurrogate;
50 import ch.ethz.inf.util.Logger;
51
52 /**
53  * Class LocalAspectManager extends AspectManager and implements a local
54  * extension manager. Upon creation, a <code>LocalAspectManager</code> registers
55  * itself as a listener of class load events into the current JoinPointManager.
56  *
57  * @version $Revision: 1.1.1.1 $
58  * @author Andrei Popovici
59  */

60 public
61 class LocalAspectManager implements AspectManager, ClassLoadListener {
62
63     static int ABORT = 0x1;
64     static int COMMIT = 0x2;
65
66   private HashMap JavaDoc txMap = new HashMap JavaDoc();
67   private Set JavaDoc theExtensions;
68   private boolean isConnectedToVM;
69   private boolean isStarted;
70   protected JoinPointManager jpm;
71
72
73   /**
74    * Create a new <code>LocalAspectManager</code>
75    * with no aspects inserted and create a <code>JoinPointManager</code>.
76    * register this extension manager as a class load listener
77    * of the current JoinPointManager.
78    */

79   protected LocalAspectManager(boolean isConnected, JVMAspectInterface ai)
80     {
81       isConnectedToVM = isConnected;
82       isStarted = false;
83       theExtensions = Collections.synchronizedSet(new HashSet JavaDoc());
84       createJoinPointManager(isConnectedToVM, ai);
85       jpm.registerListener(this);
86     }
87
88
89   /**
90    * This Method is going to be overwritten from a subclass of <code>LocalAspectManager</code>
91    * that wants to register its own <code>JoinPointManager</code>.
92    */

93   protected void createJoinPointManager(boolean isConnected, JVMAspectInterface ai)
94     {
95       jpm = new JoinPointManager(isConnected, ai, true);
96     }
97
98   /**
99    * This method has to be called before an <code>AspectManager</code> is used.
100    */

101   public synchronized void startup()
102     {
103       isStarted = true;
104       // do nothing
105
}
106
107   /**
108    * This method has to be called before an <code>AspectManager</code> is destroyed.
109    */

110   public synchronized void teardown()
111     {
112       if (!isStarted)
113     return;
114
115       withdrawAll();
116       if (jpm != null)
117         {
118           jpm.disconnectFromJVMAI();
119           jpm = null;
120     }
121       isStarted=false;
122     }
123
124
125     { Class JavaDoc c=Throwable JavaDoc.class;}
126   /** This method is called every time a new class has been successfully
127    * loaded and prepared into the system. It implements the functionality
128    * needed to update the extensions currently inserted into this extension
129    * to the current state of the system. For example, if a new class is loaded
130    * that contains join-points cross-cut by an existing crosscut E.C, the
131    * crosscut in question will be added as a listener of the JoinPointManager.
132    */

133   public void classLoaded(Class JavaDoc newClass)
134     {
135       // FIXME: exception classes are loaded when an exception is
136
// thrown. It is better not to stop the throwing of an exception
137
// with cross-cutting activity. Unfortunatelly, the test 'isAssignableFrom'
138
// was false for both exception and non-exeception classes. This
139
// seemed to be the only way around. Unclean, error prone. FIX!!
140
if (newClass.getName().endsWith("Exception"))
141     return;
142
143     synchronized(theExtensions)
144         {
145         Iterator JavaDoc i = theExtensions.iterator();
146         while (i.hasNext())
147             {
148             Aspect crtExtension = (Aspect)i.next();
149             registerCrosscuts(crtExtension,newClass);
150             }
151         }
152     }
153
154
155
156     static class TransactionGroup
157     {
158     CrosscutGroup insertGroup;
159     CrosscutGroup withdrawGroup;
160     List JavaDoc toBeInserted;
161     List JavaDoc toBeWithdrawn;
162
163     TransactionGroup()
164     {
165         insertGroup = new CrosscutGroup();
166         insertGroup.setExecuteAdvice(false);
167         withdrawGroup = new CrosscutGroup();
168         withdrawGroup.setExecuteAdvice(true);
169         toBeInserted = new Vector JavaDoc();
170         toBeWithdrawn = new Vector JavaDoc();
171     }
172     };
173
174     private TransactionGroup getTransactionGroup(Object JavaDoc transactionId)
175     {
176     TransactionGroup crtGroup = (TransactionGroup)txMap.get(transactionId);
177     if (crtGroup == null)
178         {
179         crtGroup = new TransactionGroup();
180         txMap.put(transactionId,crtGroup);
181         }
182
183     return crtGroup;
184     }
185
186     private void prepareInsertExtension(Aspect ext, Object JavaDoc transactionId)
187     {
188     // get the transaction group
189
TransactionGroup crtGroup = getTransactionGroup(transactionId);
190
191     //add ext to the list which should be inserted
192
crtGroup.toBeInserted.add(ext);
193
194     // associate all ext crosscuts to this group
195
Iterator JavaDoc i = ext.getCrosscuts().iterator();
196     while (i.hasNext())
197         {
198         Crosscut crtCrosscut = (Crosscut)i.next();
199         crtCrosscut.associateToGroup(crtGroup.insertGroup);
200         }
201     }
202
203     private void prepareWithdrawExtension(Aspect ext, Object JavaDoc transactionId)
204     {
205     // get the transaction group
206
TransactionGroup crtGroup = getTransactionGroup(transactionId);
207
208     //add ext to the list which should be withdrawn
209
crtGroup.toBeWithdrawn.add(ext);
210
211     // associate all crosscuts to this group
212
Iterator JavaDoc i = ext.getCrosscuts().iterator();
213     while (i.hasNext())
214         {
215         Crosscut crtCrosscut = (Crosscut)i.next();
216         crtCrosscut.associateToGroup(crtGroup.withdrawGroup);
217         }
218     }
219
220
221     private void finishTransaction(Object JavaDoc transactionId, int commitOrAbort)
222     {
223     // do withdraw (toBeInserted)
224
TransactionGroup crtGroup = getTransactionGroup(transactionId);
225     List JavaDoc extensionsToWithdraw = null;
226
227     if (commitOrAbort == COMMIT)
228         {
229         crtGroup.insertGroup.setExecuteAdvice(true);
230         crtGroup.withdrawGroup.setExecuteAdvice(false);
231         extensionsToWithdraw = crtGroup.toBeWithdrawn;
232         }
233     if (commitOrAbort == ABORT)
234         {
235         extensionsToWithdraw = crtGroup.toBeInserted;
236         }
237
238     Iterator JavaDoc i = extensionsToWithdraw.iterator();
239     while (i.hasNext())
240         doWithdrawExtension((Aspect)(i.next()));
241
242     txMap.remove(transactionId);
243     }
244
245
246     public void insert(Aspect x,Object JavaDoc txId)
247     {
248     if (txId == null)
249         throw new IllegalArgumentException JavaDoc("txId must be non-null");
250     prepareInsertExtension(x,txId);
251     doInsertExtension(x);
252     }
253
254     public void withdraw(Aspect x, Object JavaDoc txId)
255     {
256       if (txId == null || x == null)
257     throw new IllegalArgumentException JavaDoc("txId must be non-null");
258       prepareWithdrawExtension(x,txId);
259     }
260
261
262     public void insert(Aspect x)
263     {
264     Object JavaDoc txId = new Object JavaDoc();
265     if (txId == null || x == null)
266         throw new IllegalArgumentException JavaDoc("txId and x must be non-null");
267
268     try
269         {
270         insert(x,txId);
271         finishTransaction(txId,COMMIT);
272         }
273     catch (RuntimeException JavaDoc e)
274         {
275         finishTransaction(txId,ABORT);
276         throw e;
277         }
278
279     }
280
281     public void withdraw(Aspect x)
282     {
283         Object JavaDoc txId = new Object JavaDoc();
284         if (txId == null || x == null)
285         throw new IllegalArgumentException JavaDoc("txId must be non-null");
286
287         try
288         {
289             withdraw(x,txId);
290             finishTransaction(txId,COMMIT);
291         }
292         catch (RuntimeException JavaDoc e)
293         {
294           finishTransaction(txId,ABORT);
295           throw e;
296         }
297     }
298
299     public void commit(Object JavaDoc txId)
300     {
301     finishTransaction(txId,COMMIT);
302     }
303
304     public void abort(Object JavaDoc txId)
305     {
306     finishTransaction(txId,ABORT);
307     }
308
309   /**
310    * Insert the extension <code>ext</code> into the extension
311    * manager. This involves registering the <code>ext</code>'s
312    * crosscut into the current <code>JoinPointManager</code>.
313    */

314   public synchronized void doInsertExtension(Aspect ext) throws AspectManagerException
315     {
316
317
318     // supress notification
319
jpm.suspendListenerNotification(Thread.currentThread());
320
321     Logger.message("LocalAspectManager(" + isConnectedToVM + ").insertExtension: attempting insert, extension=" + ext);
322     try
323     {
324         ext.insertionAction(true);
325     }
326     catch (AspectInsertionException extDoesntLikeThisVM)
327     {
328         Logger.warning("LocalExtgensionManager(" + isConnectedToVM +
329                ").insertExtnesion:failed 'insertAction'",extDoesntLikeThisVM);
330         throw new AspectManagerException("Aspect ext does not wish to be inserted(" +
331                         extDoesntLikeThisVM.toString()+")");
332     }
333
334     // has extension already been inserted?
335
if (theExtensions.contains(ext))
336     {
337         Logger.message("LocalAspectManager(" + isConnectedToVM +
338                ").insertExtension: failed, ext. already existent, extension=" + ext);
339         throw new AspectManagerException("Aspect already available");
340     }
341
342     // insert into the JPM all crosscut requests generated by the extension's crosscuts.
343
// insert Crosscuts
344
registerCrosscuts(ext,null);
345
346     // bookkeeping the inserted extensions
347
theExtensions.add(ext);
348
349     // tell the extension we are finished
350
try
351     {
352         ext.insertionAction(false);
353     }
354     catch (Exception JavaDoc e)
355     {
356         Logger.warning("LocalAspectManager(" + isConnectedToVM
357                + ").insertExtension: insertAction failed, extension = " + ext);
358     }
359
360     // re-enable notification
361
jpm.resumeListenerNotification(Thread.currentThread());
362     Logger.message("LocalAspectManager(" + isConnectedToVM + ").insertExtension: done");
363   }
364
365
366   private void registerCrosscuts(Aspect ext, Class JavaDoc cls)
367     {
368     Iterator JavaDoc i = ext.getCrosscuts().iterator();
369     while (i.hasNext())
370         {
371
372         Crosscut crtCrosscut = (Crosscut)i.next();
373
374         if ( (crtCrosscut instanceof Insertable) && cls == null)
375             ((Insertable)crtCrosscut).insertionAction(true);
376
377         CrosscutRequest crtRequest = null;
378         if (cls == null)
379             crtRequest = crtCrosscut.createRequest();
380         else
381             crtRequest = crtCrosscut.createRequest(cls);
382
383         Iterator JavaDoc j = crtRequest.iterator();
384         while (j.hasNext())
385             {
386             JoinPointRequest crtJPR = (JoinPointRequest)(j.next());
387             jpm.registerListener(crtCrosscut,crtJPR);
388             }
389
390         if ( (crtCrosscut instanceof Insertable) && cls == null)
391             ((Insertable)crtCrosscut).insertionAction(false);
392
393         }
394     }
395
396   /**
397    * Unregister the crosscuts belonging to <code>ext</code>
398    * from the corresponding <code>JoinPointManager</code>
399    */

400   public synchronized void doWithdrawExtension(Aspect ext)
401     {
402     Logger.message("LocalAspectManager(" + isConnectedToVM + ").withdrawExtension: withdrawing " + ext);
403     jpm.suspendListenerNotification(Thread.currentThread());
404
405     try
406       {
407         ext.withdrawalAction(true);
408       }
409     catch (Exception JavaDoc e)
410       {
411         Logger.warning("Aspect does not wish withdrawal",e);
412       }
413
414     Iterator JavaDoc i = ext.getCrosscuts().iterator();
415     while (i.hasNext())
416       {
417         Crosscut crtCrosscut = (Crosscut)i.next();
418         jpm.unregisterListener(crtCrosscut);
419       }
420     theExtensions.remove(ext);
421
422     try
423       {
424         ext.withdrawalAction(false);
425       }
426     catch (Exception JavaDoc e)
427       {
428         Logger.message("extension " + ext + " does not wish withdrawal (end)");
429       }
430
431     jpm.resumeListenerNotification(Thread.currentThread());
432     }
433
434   /**
435    * Return the list of extensions currently
436    * inserted into the system.
437    */

438   public List JavaDoc getAllAspects()
439     {
440       return new Vector JavaDoc(theExtensions);
441     }
442
443
444   /**
445    * Return the <code>JoinPointManager</code> of this extension manager.
446    */

447   public JoinPointManager getJoinPointManager()
448     {
449       return jpm;
450     }
451
452
453   /**
454    * Return the boolean status that indicates if this extension manager is connected to the
455    * VM through its joinpoint manager or if it is the test manager and has no connection to the VM.
456    */

457   public boolean isConnectedToVM()
458     {
459       return isConnectedToVM;
460     }
461
462
463   private void withdrawAll()
464     {
465     if (jpm == null)
466         return;
467
468     jpm.suspendListenerNotification(Thread.currentThread());
469
470     if (getAllAspects() == null)
471         return;
472
473     Iterator JavaDoc i = new HashSet JavaDoc(getAllAspects()).iterator();
474     while (i.hasNext())
475         {
476         Aspect e = (Aspect)i.next();
477         withdraw(e);
478         }
479
480     jpm.resumeListenerNotification(Thread.currentThread());
481     }
482
483
484
485
486
487   /**
488    * Remove all inserted extensions from this extension manager, disconnect the joinpoint manager
489    * from the JVMAI System and deconstruct it.
490    */

491   protected void finalize()
492     {
493
494       //withdrawAll();
495
if (jpm != null)
496         {
497           jpm.disconnectFromJVMAI();
498           jpm = null;
499     }
500
501
502     }
503 }
504
505
506 //======================================================================
507
//
508
// Revision 1.13 2003/04/04 13:10:38 popovici
509
// Corrections: startup/teardown now idempotent; Bug fix in finalization: no extensions withdrawn, they will be GCed
510
//
511
// Revision 1.12 2003/03/13 14:16:09 popovici
512
// Bug fix in the query functinoality: the aspects that were seeked
513
// were taken from the list received as a parameter. When this list was received
514
// remotely, then they were <DIFFERERNT> aspects than those in the VM
515
//
516
// Revision 1.11 2003/03/04 18:36:37 popovici
517
// Organization of imprts
518
//
519
// Revision 1.10 2003/03/04 11:27:15 popovici
520
// Important refactorization step (march):
521
// - removal of 'JoinPointEvents'; JoinPoints now have the same function as events
522
// - reimplementation of the JVMAIDebuggerAspectInterface (better performance, coding conventions, removal of ProseVM
523
// structures
524
//
525
// Revision 1.9 2003/02/11 14:23:25 popovici
526
// Bug fix: 'insertion' action was performed in the JoinPointManger. This lead
527
//
528
// Revision 1.8 2003/01/27 13:27:27 pschoch
529
// LocalAspectManager prepared for lexicographical compare; allJoinpoints() returns now List
530
//
531
// Revision 1.7 2003/01/17 14:43:54 pschoch
532
// Introduction of 'query' methods in the AspectManager and its
533
// subclasses. The result set is given back in form of surrogates; 4 new tests added to ExtensionManagerTest
534
// ExtensionSystemTest
535
//
536
// Revision 1.6 2002/11/26 17:14:32 pschoch
537
// RootComponent now added (replaces RootComponent now added (replaces old ProseSystem)
538
// ProseSystem now owns and starts the Aspect interface.
539
// ProseSystem now containes a 'test' AspectManager
540
// AspectManager now owns the JoinPointManager.
541
// ExtensionManger can be 'connected' to the JVM, or disconnected. The
542
// JoinPointManager of a connected Ext.Mgr enables joinpoints; the
543
// JoinPointManger of a disconnected Ext.Mgr never enables join-points
544
// Documentation updated accordingly.
545
//
546
// Revision 1.5 2002/10/25 07:42:32 popovici
547
// Undo Chnages Philippe
548
//
549
// Revision 1.3 2002/03/28 13:48:37 popovici
550
// Mozilla-ified
551
//
552
// Revision 1.2 2002/02/05 10:17:48 smarkwal
553
// JVMDI-specific code replaced by JVMAI. Implementation-classes and reflection-package removed.
554
//
555
// Revision 1.1.1.1 2001/11/29 18:13:16 popovici
556
// Sources from runes
557
//
558
// Revision 1.1.2.12 2001/07/15 13:06:00 popovici
559
// Minor fix, exception throwing verbosified.
560
//
561
// Revision 1.1.2.11 2001/06/05 13:49:01 popovici
562
// Class now implements 'ClassLoadListener' and implments classLoad.
563
// New private method 'registerCrosscuts' added to allow 'classLoaded' to
564
// correctly update crosscuts.
565
//
566
// Revision 1.1.2.10 2001/06/01 11:29:56 popovici
567
// Logger messages added.
568
//
569
// Revision 1.1.2.9 2001/05/09 17:44:39 popovici
570
// Security whole: withdrawal Action not in a tryblock; fixed
571
//
572
// Revision 1.1.2.8 2001/03/19 10:47:49 popovici
573
// Supressing notification during insert and withdraw extension added.
574
//
575
// Revision 1.1.2.7 2001/03/16 17:29:13 mrmuller
576
// cosmetics, javadoc and exception handling changes
577
//
578
// Revision 1.1.2.6 2001/03/16 08:53:13 mrmuller
579
// Removed (unsecure) security check based only on the fact whether the Aspect class had the ExtensionPermission assigned or not. Aspect are only added to the local list of installed extensions _after_ a successful insertion.
580
//
581
// Revision 1.1.2.5 2001/02/23 16:29:55 mrmuller
582
// Added logging output
583
//
584
// Revision 1.1.2.4 2001/02/21 09:04:24 mrmuller
585
// checks if extension is trusted (ExtensionPermission is granted in policy) before it is inserted
586
//
587
// Revision 1.1.2.3 2001/02/20 09:36:26 popovici
588
// - Minor fix (might have had security implications): exceptions thrown by
589
// the extension during withdrawal have to be caught, in order to permit a
590
// complete withdrawal
591
// - Minor fix :LocalAspectManager now correctly throws an exception if
592
// the extension does not wish inserted
593
//
594
// Revision 1.1.2.2 2001/02/15 10:24:26 popovici
595
// Finalizer that withdraws currently inserted exceptions added.
596
//
597
// Revision 1.1.2.1 2001/02/07 11:51:37 popovici
598
// Initial Revision
599
//
600
Popular Tags