001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.event;
020:
021: import java.io.Serializable;
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.LinkedList;
027: import java.util.List;
028: import java.util.Map;
029:
030: import org.apache.openjpa.meta.ClassMetaData;
031: import org.apache.openjpa.meta.MetaDataDefaults;
032: import org.apache.openjpa.lib.log.Log;
033: import org.apache.openjpa.lib.util.Localizer;
034: import org.apache.openjpa.util.InvalidStateException;
035:
036: /**
037: * Manager that can be used to track and notify listeners on lifecycle events.
038: * This class is optimized for event firing rather than for adding and
039: * removing listeners, which are O(n) operations. This class also does not
040: * maintain perfect set semantics for listeners; it is possible to wind up
041: * having the same listener invoked multiple times for a single event if it
042: * is added to this manager multiple times with different classes, or with
043: * a base class and its subclass.
044: *
045: * @author Steve Kim
046: * @author Abe White
047: * @since 0.3.3
048: * @nojavadoc
049: */
050: public class LifecycleEventManager implements CallbackModes,
051: Serializable {
052:
053: private static final Exception[] EMPTY_EXCEPTIONS = new Exception[0];
054:
055: private static final Localizer _loc = Localizer
056: .forPackage(LifecycleEventManager.class);
057:
058: private Map _classListeners = null; // class -> listener list
059: private ListenerList _listeners = null;
060: private List _addListeners = new LinkedList();
061: private List _remListeners = new LinkedList();
062: private List _exceps = new LinkedList();
063: private boolean _firing = false;
064: private boolean _fail = false;
065: private boolean _failFast = false;
066:
067: /**
068: * Whether to fail after first exception when firing events to listeners.
069: */
070: public boolean isFailFast() {
071: return _failFast;
072: }
073:
074: /**
075: * Whether to fail after first exception when firing events to listeners.
076: */
077: public void setFailFast(boolean failFast) {
078: _failFast = failFast;
079: }
080:
081: /**
082: * Register a lifecycle listener for the given classes. If the classes
083: * array is null, register for all classes.
084: */
085: public synchronized void addListener(Object listener,
086: Class[] classes) {
087: if (listener == null)
088: return;
089: if (classes != null && classes.length == 0)
090: return;
091: if (_firing) {
092: _addListeners.add(listener);
093: _addListeners.add(classes);
094: return;
095: }
096:
097: if (classes == null) {
098: if (_listeners == null)
099: _listeners = new ListenerList(5);
100: _listeners.add(listener);
101: return;
102: }
103:
104: if (_classListeners == null)
105: _classListeners = new HashMap();
106: ListenerList listeners;
107: for (int i = 0; i < classes.length; i++) {
108: listeners = (ListenerList) _classListeners.get(classes[i]);
109: if (listeners == null) {
110: listeners = new ListenerList(3);
111: _classListeners.put(classes[i], listeners);
112: }
113: listeners.add(listener);
114: }
115: }
116:
117: /**
118: * Remove the given listener.
119: */
120: public synchronized void removeListener(Object listener) {
121: if (_firing) {
122: _remListeners.add(listener);
123: return;
124: }
125:
126: if (_listeners != null && _listeners.remove(listener))
127: return;
128: if (_classListeners != null) {
129: ListenerList listeners;
130: for (Iterator itr = _classListeners.values().iterator(); itr
131: .hasNext();) {
132: listeners = (ListenerList) itr.next();
133: listeners.remove(listener);
134: }
135: }
136: }
137:
138: /**
139: * Return whether there are listeners or callbacks for the given source.
140: */
141: public boolean hasPersistListeners(Object source, ClassMetaData meta) {
142: return hasHandlers(source, meta, LifecycleEvent.BEFORE_PERSIST)
143: || hasHandlers(source, meta,
144: LifecycleEvent.AFTER_PERSIST)
145: || hasHandlers(source, meta,
146: LifecycleEvent.AFTER_PERSIST_PERFORMED);
147: }
148:
149: /**
150: * Return whether there are listeners or callbacks for the given source.
151: */
152: public boolean hasDeleteListeners(Object source, ClassMetaData meta) {
153: return hasHandlers(source, meta, LifecycleEvent.BEFORE_DELETE)
154: || hasHandlers(source, meta,
155: LifecycleEvent.AFTER_DELETE)
156: || hasHandlers(source, meta,
157: LifecycleEvent.AFTER_DELETE_PERFORMED);
158: }
159:
160: /**
161: * Return whether there are listeners or callbacks for the given source.
162: */
163: public boolean hasClearListeners(Object source, ClassMetaData meta) {
164: return hasHandlers(source, meta, LifecycleEvent.BEFORE_CLEAR)
165: || hasHandlers(source, meta, LifecycleEvent.AFTER_CLEAR);
166: }
167:
168: /**
169: * Return whether there are listeners or callbacks for the given source.
170: */
171: public boolean hasLoadListeners(Object source, ClassMetaData meta) {
172: return hasHandlers(source, meta, LifecycleEvent.AFTER_LOAD);
173: }
174:
175: /**
176: * Return whether there are listeners or callbacks for the given source.
177: */
178: public boolean hasStoreListeners(Object source, ClassMetaData meta) {
179: return hasHandlers(source, meta, LifecycleEvent.BEFORE_STORE)
180: || hasHandlers(source, meta, LifecycleEvent.AFTER_STORE);
181: }
182:
183: /**
184: * Return whether there are listeners or callbacks for the given source.
185: */
186: public boolean hasUpdateListeners(Object source, ClassMetaData meta) {
187: return hasHandlers(source, meta, LifecycleEvent.BEFORE_UPDATE)
188: || hasHandlers(source, meta,
189: LifecycleEvent.AFTER_UPDATE_PERFORMED);
190: }
191:
192: /**
193: * Return whether there are listeners or callbacks for the given source.
194: */
195: public boolean hasDirtyListeners(Object source, ClassMetaData meta) {
196: return hasHandlers(source, meta, LifecycleEvent.BEFORE_DIRTY)
197: || hasHandlers(source, meta, LifecycleEvent.AFTER_DIRTY);
198: }
199:
200: /**
201: * Return whether there are listeners or callbacks for the given source.
202: */
203: public boolean hasDetachListeners(Object source, ClassMetaData meta) {
204: return hasHandlers(source, meta, LifecycleEvent.BEFORE_DETACH)
205: || hasHandlers(source, meta,
206: LifecycleEvent.AFTER_DETACH);
207: }
208:
209: /**
210: * Return whether there are listeners or callbacks for the given source.
211: */
212: public boolean hasAttachListeners(Object source, ClassMetaData meta) {
213: return hasHandlers(source, meta, LifecycleEvent.BEFORE_ATTACH)
214: || hasHandlers(source, meta,
215: LifecycleEvent.AFTER_ATTACH);
216: }
217:
218: private boolean hasHandlers(Object source, ClassMetaData meta,
219: int type) {
220: return hasCallbacks(source, meta, type)
221: || hasListeners(source, meta, type);
222: }
223:
224: /**
225: * Return true if any callbacks are registered for the given source and
226: * event type.
227: */
228: private boolean hasCallbacks(Object source, ClassMetaData meta,
229: int type) {
230: LifecycleCallbacks[] callbacks = meta.getLifecycleMetaData()
231: .getCallbacks(type);
232: if (callbacks.length == 0)
233: return false;
234: for (int i = 0; i < callbacks.length; i++)
235: if (callbacks[i].hasCallback(source, type))
236: return true;
237: return false;
238: }
239:
240: /**
241: * Return true if any listeners are registered for the given source and
242: * event type.
243: */
244: private synchronized boolean hasListeners(Object source,
245: ClassMetaData meta, int type) {
246: if (meta.getLifecycleMetaData().getIgnoreSystemListeners())
247: return false;
248: if (fireEvent(null, source, null, type, _listeners, true, null) == Boolean.TRUE)
249: return true;
250: ListenerList system = meta.getRepository().getSystemListeners();
251: if (!system.isEmpty()
252: && fireEvent(null, source, null, type, system, true,
253: null) == Boolean.TRUE)
254: return true;
255: if (_classListeners != null) {
256: Class c = source == null ? meta.getDescribedType() : source
257: .getClass();
258: do {
259: if (fireEvent(null, source, null, type,
260: (ListenerList) _classListeners.get(c), true,
261: null) == Boolean.TRUE)
262: return true;
263: c = c.getSuperclass();
264: } while (c != null && c != Object.class);
265: }
266: return false;
267: }
268:
269: /**
270: * Fire lifecycle event to all registered listeners without an argument.
271: */
272: public Exception[] fireEvent(Object source, ClassMetaData meta,
273: int type) {
274: return fireEvent(source, null, meta, type);
275: }
276:
277: /**
278: * Fire lifecycle event to all registered listeners.
279: */
280: public synchronized Exception[] fireEvent(Object source,
281: Object related, ClassMetaData meta, int type) {
282: boolean reentrant = _firing;
283: _firing = true;
284: List exceptions = (reentrant) ? new LinkedList() : _exceps;
285: MetaDataDefaults def = meta.getRepository()
286: .getMetaDataFactory().getDefaults();
287:
288: boolean callbacks = def.getCallbacksBeforeListeners(type);
289: if (callbacks)
290: makeCallbacks(source, related, meta, type, exceptions);
291:
292: LifecycleEvent ev = (LifecycleEvent) fireEvent(null, source,
293: related, type, _listeners, false, exceptions);
294:
295: if (_classListeners != null) {
296: Class c = source == null ? meta.getDescribedType() : source
297: .getClass();
298: do {
299: ev = (LifecycleEvent) fireEvent(ev, source, related,
300: type, (ListenerList) _classListeners.get(c),
301: false, exceptions);
302: c = c.getSuperclass();
303: } while (c != null && c != Object.class);
304: }
305:
306: // make system listeners
307: if (!meta.getLifecycleMetaData().getIgnoreSystemListeners()) {
308: ListenerList system = meta.getRepository()
309: .getSystemListeners();
310: fireEvent(ev, source, related, type, system, false,
311: exceptions);
312: }
313:
314: if (!callbacks)
315: makeCallbacks(source, related, meta, type, exceptions);
316:
317: // create return array before clearing exceptions
318: Exception[] ret;
319: if (exceptions.isEmpty())
320: ret = EMPTY_EXCEPTIONS;
321: else
322: ret = (Exception[]) exceptions
323: .toArray(new Exception[exceptions.size()]);
324:
325: // if this wasn't a reentrant call, catch up with calls to add
326: // and remove listeners made while firing
327: if (!reentrant) {
328: _firing = false;
329: _fail = false;
330: if (!_addListeners.isEmpty())
331: for (Iterator itr = _addListeners.iterator(); itr
332: .hasNext();)
333: addListener(itr.next(), (Class[]) itr.next());
334: if (!_remListeners.isEmpty())
335: for (Iterator itr = _remListeners.iterator(); itr
336: .hasNext();)
337: removeListener(itr.next());
338: _addListeners.clear();
339: _remListeners.clear();
340: _exceps.clear();
341: }
342: return ret;
343: }
344:
345: /**
346: * Make callbacks, recording any exceptions in the given collection.
347: */
348: private void makeCallbacks(Object source, Object related,
349: ClassMetaData meta, int type, Collection exceptions) {
350: // make lifecycle callbacks
351: LifecycleCallbacks[] callbacks = meta.getLifecycleMetaData()
352: .getCallbacks(type);
353: for (int i = 0; !_fail && i < callbacks.length; i++) {
354: try {
355: callbacks[i].makeCallback(source, related, type);
356: } catch (Exception e) {
357: exceptions.add(e);
358: if (_failFast)
359: _fail = true;
360: }
361: }
362: }
363:
364: /**
365: * Fire an event with the given source and type to the given list of
366: * listeners. The event may have already been constructed.
367: */
368: private Object fireEvent(LifecycleEvent ev, Object source,
369: Object rel, int type, ListenerList listeners, boolean mock,
370: List exceptions) {
371: if (listeners == null || !listeners.hasListeners(type))
372: return null;
373:
374: Object listener;
375: boolean responds;
376: for (int i = 0, size = listeners.size(); !_fail && i < size; i++) {
377: listener = listeners.get(i);
378: if (size == 1)
379: responds = true;
380: else if (listener instanceof ListenerAdapter) {
381: responds = ((ListenerAdapter) listener)
382: .respondsTo(type);
383: if (!responds)
384: continue;
385: } else
386: responds = false;
387:
388: try {
389: switch (type) {
390: case LifecycleEvent.BEFORE_CLEAR:
391: case LifecycleEvent.AFTER_CLEAR:
392: if (responds || listener instanceof ClearListener) {
393: if (mock)
394: return Boolean.TRUE;
395: if (ev == null)
396: ev = new LifecycleEvent(source, type);
397: if (type == LifecycleEvent.BEFORE_CLEAR)
398: ((ClearListener) listener).beforeClear(ev);
399: else
400: ((ClearListener) listener).afterClear(ev);
401: }
402: break;
403: case LifecycleEvent.BEFORE_PERSIST:
404: case LifecycleEvent.AFTER_PERSIST:
405: if (responds || listener instanceof PersistListener) {
406: if (mock)
407: return Boolean.TRUE;
408: if (ev == null)
409: ev = new LifecycleEvent(source, type);
410: if (type == LifecycleEvent.BEFORE_PERSIST)
411: ((PersistListener) listener)
412: .beforePersist(ev);
413: else
414: ((PersistListener) listener)
415: .afterPersist(ev);
416: }
417: break;
418: case LifecycleEvent.BEFORE_DELETE:
419: case LifecycleEvent.AFTER_DELETE:
420: if (responds || listener instanceof DeleteListener) {
421: if (mock)
422: return Boolean.TRUE;
423: if (ev == null)
424: ev = new LifecycleEvent(source, type);
425: if (type == LifecycleEvent.BEFORE_DELETE)
426: ((DeleteListener) listener)
427: .beforeDelete(ev);
428: else
429: ((DeleteListener) listener).afterDelete(ev);
430: }
431: break;
432: case LifecycleEvent.BEFORE_DIRTY:
433: case LifecycleEvent.AFTER_DIRTY:
434: case LifecycleEvent.BEFORE_DIRTY_FLUSHED:
435: case LifecycleEvent.AFTER_DIRTY_FLUSHED:
436: if (responds || listener instanceof DirtyListener) {
437: if (mock)
438: return Boolean.TRUE;
439: if (ev == null)
440: ev = new LifecycleEvent(source, type);
441: switch (type) {
442: case LifecycleEvent.BEFORE_DIRTY:
443: ((DirtyListener) listener).beforeDirty(ev);
444: break;
445: case LifecycleEvent.AFTER_DIRTY:
446: ((DirtyListener) listener).afterDirty(ev);
447: break;
448: case LifecycleEvent.BEFORE_DIRTY_FLUSHED:
449: ((DirtyListener) listener)
450: .beforeDirtyFlushed(ev);
451: break;
452: case LifecycleEvent.AFTER_DIRTY_FLUSHED:
453: ((DirtyListener) listener)
454: .afterDirtyFlushed(ev);
455: break;
456: }
457: }
458: break;
459: case LifecycleEvent.AFTER_LOAD:
460: case LifecycleEvent.AFTER_REFRESH:
461: if (responds || listener instanceof LoadListener) {
462: if (mock)
463: return Boolean.TRUE;
464: if (ev == null)
465: ev = new LifecycleEvent(source, type);
466: if (type == LifecycleEvent.AFTER_LOAD)
467: ((LoadListener) listener).afterLoad(ev);
468: else
469: ((LoadListener) listener).afterRefresh(ev);
470: }
471: break;
472: case LifecycleEvent.BEFORE_STORE:
473: case LifecycleEvent.AFTER_STORE:
474: if (responds || listener instanceof StoreListener) {
475: if (mock)
476: return Boolean.TRUE;
477: if (ev == null)
478: ev = new LifecycleEvent(source, type);
479: if (type == LifecycleEvent.BEFORE_STORE)
480: ((StoreListener) listener).beforeStore(ev);
481: else
482: ((StoreListener) listener).afterStore(ev);
483: }
484: break;
485: case LifecycleEvent.BEFORE_DETACH:
486: case LifecycleEvent.AFTER_DETACH:
487: if (responds || listener instanceof DetachListener) {
488: if (mock)
489: return Boolean.TRUE;
490: if (ev == null)
491: ev = new LifecycleEvent(source, rel, type);
492: if (type == LifecycleEvent.BEFORE_DETACH)
493: ((DetachListener) listener)
494: .beforeDetach(ev);
495: else
496: ((DetachListener) listener).afterDetach(ev);
497: }
498: break;
499: case LifecycleEvent.BEFORE_ATTACH:
500: case LifecycleEvent.AFTER_ATTACH:
501: if (responds || listener instanceof AttachListener) {
502: if (mock)
503: return Boolean.TRUE;
504: if (ev == null)
505: ev = new LifecycleEvent(source, rel, type);
506: if (type == LifecycleEvent.BEFORE_ATTACH)
507: ((AttachListener) listener)
508: .beforeAttach(ev);
509: else
510: ((AttachListener) listener).afterAttach(ev);
511: }
512: break;
513:
514: case LifecycleEvent.AFTER_PERSIST_PERFORMED:
515: if (responds
516: || listener instanceof PostPersistListener) {
517: if (mock)
518: return Boolean.TRUE;
519: if (ev == null)
520: ev = new LifecycleEvent(source, rel, type);
521: ((PostPersistListener) listener)
522: .afterPersistPerformed(ev);
523: }
524: break;
525: case LifecycleEvent.BEFORE_UPDATE:
526: case LifecycleEvent.AFTER_UPDATE_PERFORMED:
527: if (responds || listener instanceof UpdateListener) {
528: if (mock)
529: return Boolean.TRUE;
530: if (ev == null)
531: ev = new LifecycleEvent(source, rel, type);
532: if (type == LifecycleEvent.BEFORE_UPDATE)
533: ((UpdateListener) listener)
534: .beforeUpdate(ev);
535: else
536: ((UpdateListener) listener)
537: .afterUpdatePerformed(ev);
538: }
539: break;
540: case LifecycleEvent.AFTER_DELETE_PERFORMED:
541: if (responds
542: || listener instanceof PostDeleteListener) {
543: if (mock)
544: return Boolean.TRUE;
545: if (ev == null)
546: ev = new LifecycleEvent(source, rel, type);
547: ((PostDeleteListener) listener)
548: .afterDeletePerformed(ev);
549: }
550: break;
551: default:
552: throw new InvalidStateException(_loc.get(
553: "unknown-lifecycle-event", Integer
554: .toString(type)));
555: }
556: } catch (Exception e) {
557: exceptions.add(e);
558: if (_failFast)
559: _fail = true;
560: }
561: }
562: return ev;
563: }
564:
565: /**
566: * Interface that facades to other lifecycle listener interfaces can
567: * implement to choose which events to respond to based on their delegate.
568: * This is more efficient than registering as a listener for all events
569: * but only responding to some.
570: */
571: public static interface ListenerAdapter {
572:
573: /**
574: * Return whether this instance responds to the given event type from
575: * {@link LifecycleEvent}.
576: */
577: public boolean respondsTo(int eventType);
578: }
579:
580: /**
581: * Extended list that tracks what event types its elements care about.
582: * Maintains set semantics as well.
583: */
584: public static class ListenerList extends ArrayList {
585:
586: private int _types = 0;
587:
588: public ListenerList(int size) {
589: super (size);
590: }
591:
592: public ListenerList(ListenerList copy) {
593: super (copy);
594: _types = copy._types;
595: }
596:
597: public boolean hasListeners(int type) {
598: return (_types & (2 << type)) > 0;
599: }
600:
601: public boolean add(Object listener) {
602: if (contains(listener))
603: return false;
604: super .add(listener);
605: _types |= getEventTypes(listener);
606: return true;
607: }
608:
609: public boolean remove(Object listener) {
610: if (!super .remove(listener))
611: return false;
612:
613: // recompute types mask
614: _types = 0;
615: for (int i = 0; i < size(); i++)
616: _types |= getEventTypes(get(i));
617: return true;
618: }
619:
620: /**
621: * Return a mask of the event types the given listener processes.
622: */
623: private static int getEventTypes(Object listener) {
624: int types = 0;
625: if (listener instanceof ListenerAdapter) {
626: ListenerAdapter adapter = (ListenerAdapter) listener;
627: for (int i = 0; i < LifecycleEvent.ALL_EVENTS.length; i++)
628: if (adapter
629: .respondsTo(LifecycleEvent.ALL_EVENTS[i]))
630: types |= 2 << LifecycleEvent.ALL_EVENTS[i];
631: return types;
632: }
633:
634: if (listener instanceof PersistListener) {
635: types |= 2 << LifecycleEvent.BEFORE_PERSIST;
636: types |= 2 << LifecycleEvent.AFTER_PERSIST;
637: }
638: if (listener instanceof ClearListener) {
639: types |= 2 << LifecycleEvent.BEFORE_CLEAR;
640: types |= 2 << LifecycleEvent.AFTER_CLEAR;
641: }
642: if (listener instanceof DeleteListener) {
643: types |= 2 << LifecycleEvent.BEFORE_DELETE;
644: types |= 2 << LifecycleEvent.AFTER_DELETE;
645: }
646: if (listener instanceof DirtyListener) {
647: types |= 2 << LifecycleEvent.BEFORE_DIRTY;
648: types |= 2 << LifecycleEvent.AFTER_DIRTY;
649: types |= 2 << LifecycleEvent.BEFORE_DIRTY_FLUSHED;
650: types |= 2 << LifecycleEvent.AFTER_DIRTY_FLUSHED;
651: }
652: if (listener instanceof LoadListener) {
653: types |= 2 << LifecycleEvent.AFTER_LOAD;
654: types |= 2 << LifecycleEvent.AFTER_REFRESH;
655: }
656: if (listener instanceof StoreListener) {
657: types |= 2 << LifecycleEvent.BEFORE_STORE;
658: types |= 2 << LifecycleEvent.AFTER_STORE;
659: }
660: if (listener instanceof DetachListener) {
661: types |= 2 << LifecycleEvent.BEFORE_DETACH;
662: types |= 2 << LifecycleEvent.AFTER_DETACH;
663: }
664: if (listener instanceof AttachListener) {
665: types |= 2 << LifecycleEvent.BEFORE_ATTACH;
666: types |= 2 << LifecycleEvent.AFTER_ATTACH;
667: }
668: return types;
669: }
670: }
671: }
|