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: LocalAspectManager.java,v 1.2 2005/06/25 17:44:52 anicoara Exp $
022: // =====================================================================
023: //
024: // (history at end)
025: //
026:
027: package ch.ethz.prose;
028:
029: // used packages
030: import java.util.Collections;
031: import java.util.HashSet;
032: import java.util.Iterator;
033: import java.util.List;
034: import java.util.Set;
035: import java.util.Vector;
036: import java.util.HashMap;
037:
038: import ch.ethz.jvmai.JVMAspectInterface;
039: import ch.ethz.prose.crosscut.Crosscut;
040: import ch.ethz.prose.crosscut.CrosscutRequest;
041: import ch.ethz.prose.crosscut.CrosscutGroup;
042: import ch.ethz.prose.engine.ClassLoadListener;
043: import ch.ethz.prose.engine.JoinPointManager;
044: import ch.ethz.prose.engine.JoinPointRequest;
045: import ch.ethz.inf.util.Logger;
046:
047: /**
048: * Class LocalAspectManager extends AspectManager and implements a local
049: * extension manager. Upon creation, a <code>LocalAspectManager</code> registers
050: * itself as a listener of class load events into the current JoinPointManager.
051: *
052: * @version $Revision: 1.2 $
053: * @author Andrei Popovici
054: */
055: public class LocalAspectManager implements AspectManager,
056: ClassLoadListener {
057:
058: static int ABORT = 0x1;
059: static int COMMIT = 0x2;
060:
061: private HashMap txMap = new HashMap();
062: private Set theExtensions;
063: private boolean isConnectedToVM;
064: private boolean isStarted;
065: protected JoinPointManager jpm;
066:
067: /**
068: * Create a new <code>LocalAspectManager</code>
069: * with no aspects inserted and create a <code>JoinPointManager</code>.
070: * register this extension manager as a class load listener
071: * of the current JoinPointManager.
072: */
073: protected LocalAspectManager(boolean isConnected,
074: JVMAspectInterface ai) {
075: isConnectedToVM = isConnected;
076: isStarted = false;
077: theExtensions = Collections.synchronizedSet(new HashSet());
078: createJoinPointManager(isConnectedToVM, ai);
079: jpm.registerListener(this );
080: }
081:
082: /**
083: * This Method is going to be overwritten from a subclass of <code>LocalAspectManager</code>
084: * that wants to register its own <code>JoinPointManager</code>.
085: */
086: protected void createJoinPointManager(boolean isConnected,
087: JVMAspectInterface ai) {
088: jpm = new JoinPointManager(isConnected, ai, true);
089: }
090:
091: /**
092: * This method has to be called before an <code>AspectManager</code> is used.
093: */
094: public synchronized void startup() {
095: isStarted = true;
096: // do nothing
097: }
098:
099: /**
100: * This method has to be called before an <code>AspectManager</code> is destroyed.
101: */
102: public synchronized void teardown() {
103: if (!isStarted)
104: return;
105:
106: withdrawAll();
107: if (jpm != null) {
108: jpm.disconnectFromJVMAI();
109: jpm = null;
110: }
111: isStarted = false;
112: }
113:
114: {
115: Class c = Throwable.class;
116: }
117:
118: /** This method is called every time a new class has been successfully
119: * loaded and prepared into the system. It implements the functionality
120: * needed to update the extensions currently inserted into this extension
121: * to the current state of the system. For example, if a new class is loaded
122: * that contains join-points cross-cut by an existing crosscut E.C, the
123: * crosscut in question will be added as a listener of the JoinPointManager.
124: */
125: public void classLoaded(Class newClass) {
126: // FIXME: exception classes are loaded when an exception is
127: // thrown. It is better not to stop the throwing of an exception
128: // with cross-cutting activity. Unfortunatelly, the test 'isAssignableFrom'
129: // was false for both exception and non-exeception classes. This
130: // seemed to be the only way around. Unclean, error prone. FIX!!
131: if (newClass.getName().endsWith("Exception"))
132: return;
133:
134: synchronized (theExtensions) {
135: Iterator i = theExtensions.iterator();
136: while (i.hasNext()) {
137: Aspect crtExtension = (Aspect) i.next();
138: registerCrosscuts(crtExtension, newClass);
139: }
140: }
141: }
142:
143: static class TransactionGroup {
144: CrosscutGroup insertGroup;
145: CrosscutGroup withdrawGroup;
146: List toBeInserted;
147: List toBeWithdrawn;
148:
149: TransactionGroup() {
150: insertGroup = new CrosscutGroup();
151: insertGroup.setExecuteAdvice(false);
152: withdrawGroup = new CrosscutGroup();
153: withdrawGroup.setExecuteAdvice(true);
154: toBeInserted = new Vector();
155: toBeWithdrawn = new Vector();
156: }
157: };
158:
159: private TransactionGroup getTransactionGroup(Object transactionId) {
160: TransactionGroup crtGroup = (TransactionGroup) txMap
161: .get(transactionId);
162: if (crtGroup == null) {
163: crtGroup = new TransactionGroup();
164: txMap.put(transactionId, crtGroup);
165: }
166:
167: return crtGroup;
168: }
169:
170: private void prepareInsertExtension(Aspect ext, Object transactionId) {
171: // get the transaction group
172: TransactionGroup crtGroup = getTransactionGroup(transactionId);
173:
174: //add ext to the list which should be inserted
175: crtGroup.toBeInserted.add(ext);
176:
177: // associate all ext crosscuts to this group
178: Iterator i = ext.getCrosscuts().iterator();
179: while (i.hasNext()) {
180: Crosscut crtCrosscut = (Crosscut) i.next();
181: crtCrosscut.associateToGroup(crtGroup.insertGroup);
182: }
183: }
184:
185: private void prepareWithdrawExtension(Aspect ext,
186: Object transactionId) {
187: // get the transaction group
188: TransactionGroup crtGroup = getTransactionGroup(transactionId);
189:
190: //add ext to the list which should be withdrawn
191: crtGroup.toBeWithdrawn.add(ext);
192:
193: // associate all crosscuts to this group
194: Iterator i = ext.getCrosscuts().iterator();
195: while (i.hasNext()) {
196: Crosscut crtCrosscut = (Crosscut) i.next();
197: crtCrosscut.associateToGroup(crtGroup.withdrawGroup);
198: }
199: }
200:
201: private void finishTransaction(Object transactionId,
202: int commitOrAbort) {
203: // do withdraw (toBeInserted)
204: TransactionGroup crtGroup = getTransactionGroup(transactionId);
205: List extensionsToWithdraw = null;
206:
207: if (commitOrAbort == COMMIT) {
208: crtGroup.insertGroup.setExecuteAdvice(true);
209: crtGroup.withdrawGroup.setExecuteAdvice(false);
210: extensionsToWithdraw = crtGroup.toBeWithdrawn;
211: }
212: if (commitOrAbort == ABORT) {
213: extensionsToWithdraw = crtGroup.toBeInserted;
214: }
215:
216: Iterator i = extensionsToWithdraw.iterator();
217: while (i.hasNext())
218: doWithdrawExtension((Aspect) (i.next()));
219:
220: txMap.remove(transactionId);
221: }
222:
223: public void insert(Aspect x, Object txId) {
224: if (txId == null)
225: throw new IllegalArgumentException("txId must be non-null");
226: prepareInsertExtension(x, txId);
227: doInsertExtension(x);
228: }
229:
230: public void withdraw(Aspect x, Object txId) {
231: if (txId == null || x == null)
232: throw new IllegalArgumentException("txId must be non-null");
233: prepareWithdrawExtension(x, txId);
234: }
235:
236: public void insert(Aspect x) {
237: Object txId = new Object();
238: if (txId == null || x == null)
239: throw new IllegalArgumentException(
240: "txId and x must be non-null");
241:
242: try {
243: insert(x, txId);
244: finishTransaction(txId, COMMIT);
245: } catch (RuntimeException e) {
246: finishTransaction(txId, ABORT);
247: throw e;
248: }
249:
250: }
251:
252: public void withdraw(Aspect x) {
253: Object txId = new Object();
254: if (txId == null || x == null)
255: throw new IllegalArgumentException("txId must be non-null");
256:
257: try {
258: withdraw(x, txId);
259: finishTransaction(txId, COMMIT);
260: } catch (RuntimeException e) {
261: finishTransaction(txId, ABORT);
262: throw e;
263: }
264: }
265:
266: public void commit(Object txId) {
267: finishTransaction(txId, COMMIT);
268: }
269:
270: public void abort(Object txId) {
271: finishTransaction(txId, ABORT);
272: }
273:
274: /**
275: * Insert the extension <code>ext</code> into the extension
276: * manager. This involves registering the <code>ext</code>'s
277: * crosscut into the current <code>JoinPointManager</code>.
278: */
279: public synchronized void doInsertExtension(Aspect ext)
280: throws AspectManagerException {
281:
282: // supress notification
283: jpm.suspendListenerNotification(Thread.currentThread());
284:
285: Logger.message("LocalAspectManager(" + isConnectedToVM
286: + ").insertExtension: attempting insert, extension="
287: + ext);
288: try {
289: ext.insertionAction(true);
290: } catch (AspectInsertionException extDoesntLikeThisVM) {
291: Logger.warning("LocalExtgensionManager(" + isConnectedToVM
292: + ").insertExtnesion:failed 'insertAction'",
293: extDoesntLikeThisVM);
294: throw new AspectManagerException(
295: "Aspect ext does not wish to be inserted("
296: + extDoesntLikeThisVM.toString() + ")");
297: }
298:
299: // has extension already been inserted?
300: if (theExtensions.contains(ext)) {
301: Logger
302: .message("LocalAspectManager("
303: + isConnectedToVM
304: + ").insertExtension: failed, ext. already existent, extension="
305: + ext);
306: throw new AspectManagerException("Aspect already available");
307: }
308:
309: // insert into the JPM all crosscut requests generated by the extension's crosscuts.
310: // insert Crosscuts
311: registerCrosscuts(ext, null);
312:
313: // bookkeeping the inserted extensions
314: theExtensions.add(ext);
315:
316: // tell the extension we are finished
317: try {
318: ext.insertionAction(false);
319: } catch (Exception e) {
320: Logger
321: .warning("LocalAspectManager("
322: + isConnectedToVM
323: + ").insertExtension: insertAction failed, extension = "
324: + ext);
325: }
326:
327: // re-enable notification
328: jpm.resumeListenerNotification(Thread.currentThread());
329: Logger.message("LocalAspectManager(" + isConnectedToVM
330: + ").insertExtension: done");
331: }
332:
333: private void registerCrosscuts(Aspect ext, Class cls) {
334: //System.out.println("LocalAspectManager - Aspect = " + ext.toString());
335: //System.out.println("LocalAspectManager - Class = " + cls);
336: Iterator i = ext.getCrosscuts().iterator();
337: while (i.hasNext()) {
338:
339: Crosscut crtCrosscut = (Crosscut) i.next();
340: //System.out.println("LocalAspectManager - crtCrosscut = " + crtCrosscut.toString());
341:
342: if ((crtCrosscut instanceof Insertable) && cls == null)
343: ((Insertable) crtCrosscut).insertionAction(true);
344:
345: CrosscutRequest crtRequest = null;
346: if (cls == null)
347: // This method is used by first use of this crosscut
348: crtRequest = crtCrosscut.createRequest();
349: else
350: // This method is used upon loading of new classes in the VM
351: crtRequest = crtCrosscut.createRequest(cls);
352:
353: Iterator j = crtRequest.iterator();
354: while (j.hasNext()) {
355: //System.out.println("LocalAspectManager - crtCrosscut.iterator = " + crtRequest.toString());
356: JoinPointRequest crtJPR = (JoinPointRequest) (j.next());
357: jpm.registerListener(crtCrosscut, crtJPR);
358: }
359:
360: if ((crtCrosscut instanceof Insertable) && cls == null)
361: ((Insertable) crtCrosscut).insertionAction(false);
362:
363: }
364: }
365:
366: /**
367: * Unregister the crosscuts belonging to <code>ext</code>
368: * from the corresponding <code>JoinPointManager</code>
369: */
370: public synchronized void doWithdrawExtension(Aspect ext) {
371: Logger.message("LocalAspectManager(" + isConnectedToVM
372: + ").withdrawExtension: withdrawing " + ext);
373: jpm.suspendListenerNotification(Thread.currentThread());
374:
375: try {
376: ext.withdrawalAction(true);
377: } catch (Exception e) {
378: Logger.warning("Aspect does not wish withdrawal", e);
379: }
380:
381: Iterator i = ext.getCrosscuts().iterator();
382: while (i.hasNext()) {
383: Crosscut crtCrosscut = (Crosscut) i.next();
384: jpm.unregisterListener(crtCrosscut);
385: }
386: theExtensions.remove(ext);
387:
388: try {
389: ext.withdrawalAction(false);
390: } catch (Exception e) {
391: Logger.message("extension " + ext
392: + " does not wish withdrawal (end)");
393: }
394:
395: jpm.resumeListenerNotification(Thread.currentThread());
396: }
397:
398: /**
399: * Return the list of extensions currently
400: * inserted into the system.
401: */
402: public List getAllAspects() {
403: return new Vector(theExtensions);
404: }
405:
406: /**
407: * Return the <code>JoinPointManager</code> of this extension manager.
408: */
409: public JoinPointManager getJoinPointManager() {
410: return jpm;
411: }
412:
413: /**
414: * Return the boolean status that indicates if this extension manager is connected to the
415: * VM through its joinpoint manager or if it is the test manager and has no connection to the VM.
416: */
417: public boolean isConnectedToVM() {
418: return isConnectedToVM;
419: }
420:
421: private void withdrawAll() {
422: if (jpm == null)
423: return;
424:
425: jpm.suspendListenerNotification(Thread.currentThread());
426:
427: if (getAllAspects() == null)
428: return;
429:
430: Iterator i = new HashSet(getAllAspects()).iterator();
431: while (i.hasNext()) {
432: Aspect e = (Aspect) i.next();
433: withdraw(e);
434: }
435:
436: jpm.resumeListenerNotification(Thread.currentThread());
437: }
438:
439: /**
440: * Remove all inserted extensions from this extension manager, disconnect the joinpoint manager
441: * from the JVMAI System and deconstruct it.
442: */
443: protected void finalize() {
444:
445: //withdrawAll();
446: if (jpm != null) {
447: jpm.disconnectFromJVMAI();
448: jpm = null;
449: }
450:
451: }
452: }
453:
454: //======================================================================
455: //
456: // Revision 1.13 2003/04/04 13:10:38 popovici
457: // Corrections: startup/teardown now idempotent; Bug fix in finalization: no extensions withdrawn, they will be GCed
458: //
459: // Revision 1.12 2003/03/13 14:16:09 popovici
460: // Bug fix in the query functinoality: the aspects that were seeked
461: // were taken from the list received as a parameter. When this list was received
462: // remotely, then they were <DIFFERERNT> aspects than those in the VM
463: //
464: // Revision 1.11 2003/03/04 18:36:37 popovici
465: // Organization of imprts
466: //
467: // Revision 1.10 2003/03/04 11:27:15 popovici
468: // Important refactorization step (march):
469: // - removal of 'JoinPointEvents'; JoinPoints now have the same function as events
470: // - reimplementation of the JVMAIDebuggerAspectInterface (better performance, coding conventions, removal of ProseVM
471: // structures
472: //
473: // Revision 1.9 2003/02/11 14:23:25 popovici
474: // Bug fix: 'insertion' action was performed in the JoinPointManger. This lead
475: //
476: // Revision 1.8 2003/01/27 13:27:27 pschoch
477: // LocalAspectManager prepared for lexicographical compare; allJoinpoints() returns now List
478: //
479: // Revision 1.7 2003/01/17 14:43:54 pschoch
480: // Introduction of 'query' methods in the AspectManager and its
481: // subclasses. The result set is given back in form of surrogates; 4 new tests added to ExtensionManagerTest
482: // ExtensionSystemTest
483: //
484: // Revision 1.6 2002/11/26 17:14:32 pschoch
485: // RootComponent now added (replaces RootComponent now added (replaces old ProseSystem)
486: // ProseSystem now owns and starts the Aspect interface.
487: // ProseSystem now containes a 'test' AspectManager
488: // AspectManager now owns the JoinPointManager.
489: // ExtensionManger can be 'connected' to the JVM, or disconnected. The
490: // JoinPointManager of a connected Ext.Mgr enables joinpoints; the
491: // JoinPointManger of a disconnected Ext.Mgr never enables join-points
492: // Documentation updated accordingly.
493: //
494: // Revision 1.5 2002/10/25 07:42:32 popovici
495: // Undo Chnages Philippe
496: //
497: // Revision 1.3 2002/03/28 13:48:37 popovici
498: // Mozilla-ified
499: //
500: // Revision 1.2 2002/02/05 10:17:48 smarkwal
501: // JVMDI-specific code replaced by JVMAI. Implementation-classes and reflection-package removed.
502: //
503: // Revision 1.1.1.1 2001/11/29 18:13:16 popovici
504: // Sources from runes
505: //
506: // Revision 1.1.2.12 2001/07/15 13:06:00 popovici
507: // Minor fix, exception throwing verbosified.
508: //
509: // Revision 1.1.2.11 2001/06/05 13:49:01 popovici
510: // Class now implements 'ClassLoadListener' and implments classLoad.
511: // New private method 'registerCrosscuts' added to allow 'classLoaded' to
512: // correctly update crosscuts.
513: //
514: // Revision 1.1.2.10 2001/06/01 11:29:56 popovici
515: // Logger messages added.
516: //
517: // Revision 1.1.2.9 2001/05/09 17:44:39 popovici
518: // Security whole: withdrawal Action not in a tryblock; fixed
519: //
520: // Revision 1.1.2.8 2001/03/19 10:47:49 popovici
521: // Supressing notification during insert and withdraw extension added.
522: //
523: // Revision 1.1.2.7 2001/03/16 17:29:13 mrmuller
524: // cosmetics, javadoc and exception handling changes
525: //
526: // Revision 1.1.2.6 2001/03/16 08:53:13 mrmuller
527: // 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.
528: //
529: // Revision 1.1.2.5 2001/02/23 16:29:55 mrmuller
530: // Added logging output
531: //
532: // Revision 1.1.2.4 2001/02/21 09:04:24 mrmuller
533: // checks if extension is trusted (ExtensionPermission is granted in policy) before it is inserted
534: //
535: // Revision 1.1.2.3 2001/02/20 09:36:26 popovici
536: // - Minor fix (might have had security implications): exceptions thrown by
537: // the extension during withdrawal have to be caught, in order to permit a
538: // complete withdrawal
539: // - Minor fix :LocalAspectManager now correctly throws an exception if
540: // the extension does not wish inserted
541: //
542: // Revision 1.1.2.2 2001/02/15 10:24:26 popovici
543: // Finalizer that withdraws currently inserted exceptions added.
544: //
545: // Revision 1.1.2.1 2001/02/07 11:51:37 popovici
546: // Initial Revision
547: //
|