001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo;
012:
013: /**
014: * This keeps track of lists of LifecycleListener's for the different
015: * LifecycleEvent's. It implements a copy-on-write scheme so the lists on the
016: * PMF can be shared by all PMs until first modified. Any modification to
017: * a LifecycleListenerManager via add or remove will return a reference
018: * to a new LifecycleListenerManager with the change applied. If a
019: * LifecycleListenerManager becomes empty then null is returned.
020: */
021: public class LifecycleListenerManager {
022:
023: private PreStoreNode preStoreList;
024: private PostStoreNode postStoreList;
025: private DeleteNode deleteList;
026:
027: /**
028: * Create new LifecycleListenerManager containinhg toAdd.
029: */
030: public LifecycleListenerManager(LifecycleListener toAdd) {
031: addImp(toAdd);
032: }
033:
034: /**
035: * Copy constructor.
036: */
037: private LifecycleListenerManager(LifecycleListenerManager toCopy) {
038: preStoreList = toCopy.preStoreList == null ? null
039: : toCopy.preStoreList.copy();
040: postStoreList = toCopy.postStoreList == null ? null
041: : toCopy.postStoreList.copy();
042: deleteList = toCopy.deleteList == null ? null
043: : toCopy.deleteList.copy();
044: }
045:
046: /**
047: * Return a copy of this LifecycleListenerManager with l added.
048: */
049: public LifecycleListenerManager add(LifecycleListener l) {
050: return new LifecycleListenerManager(this ).addImp(l);
051: }
052:
053: private LifecycleListenerManager addImp(LifecycleListener l) {
054: if (l instanceof PreStoreLifecycleListener) {
055: preStoreList = new PreStoreNode(
056: (PreStoreLifecycleListener) l, preStoreList);
057: }
058: if (l instanceof PostStoreLifecycleListener) {
059: postStoreList = new PostStoreNode(
060: (PostStoreLifecycleListener) l, postStoreList);
061: }
062: if (l instanceof DeleteLifecycleListener) {
063: deleteList = new DeleteNode((DeleteLifecycleListener) l,
064: deleteList);
065: }
066: return this ;
067: }
068:
069: /**
070: * Return a copy of this LifecycleListenerManager with l removed or
071: * null if the resulting LifecycleListenerManager would contain no
072: * listeners.
073: */
074: public LifecycleListenerManager remove(LifecycleListener l) {
075: return new LifecycleListenerManager(this ).removeImp(l);
076: }
077:
078: private LifecycleListenerManager removeImp(LifecycleListener l) {
079: if (l instanceof PreStoreLifecycleListener) {
080: PreStoreNode prev = null;
081: for (PreStoreNode i = preStoreList; i != null; i = i.next) {
082: if (i.listener == l) {
083: if (prev == null) {
084: preStoreList = i.next;
085: } else {
086: prev.next = i.next;
087: }
088: }
089: prev = i;
090: }
091: }
092: if (l instanceof DeleteLifecycleListener) {
093: DeleteNode prev = null;
094: for (DeleteNode i = deleteList; i != null; i = i.next) {
095: if (i.listener == l) {
096: if (prev == null) {
097: deleteList = i.next;
098: } else {
099: prev.next = i.next;
100: }
101: }
102: prev = i;
103: }
104: }
105: if (preStoreList == null && deleteList == null) {
106: return null;
107: }
108: return this ;
109: }
110:
111: /**
112: * Fire a preStore event returning true if there were any listeners.
113: */
114: public boolean firePreStore(Object o) {
115: if (preStoreList == null) {
116: return false;
117: }
118: LifecycleEvent ev = new LifecycleEvent(o,
119: LifecycleEvent.PRESTORE);
120: for (PreStoreNode i = preStoreList; i != null; i = i.next) {
121: i.listener.preStore(ev);
122: }
123: return true;
124: }
125:
126: /**
127: * Fire a postStore event.
128: */
129: public void firePostStore(Object o) {
130: if (postStoreList == null) {
131: return;
132: }
133: LifecycleEvent ev = new LifecycleEvent(o,
134: LifecycleEvent.POSTSTORE);
135: for (PostStoreNode i = postStoreList; i != null; i = i.next) {
136: i.listener.postStore(ev);
137: }
138: }
139:
140: /**
141: * Fire a delete event.
142: */
143: public void fireDelete(Object o) {
144: if (deleteList == null) {
145: return;
146: }
147: LifecycleEvent ev = new LifecycleEvent(o, LifecycleEvent.DELETE);
148: for (DeleteNode i = deleteList; i != null; i = i.next) {
149: i.listener.delete(ev);
150: }
151: }
152:
153: /**
154: * Do we have any postStore listeners?
155: */
156: public boolean hasPostStoreListeners() {
157: return postStoreList != null;
158: }
159:
160: private static class PreStoreNode {
161:
162: public PreStoreLifecycleListener listener;
163: public PreStoreNode next;
164:
165: public PreStoreNode(PreStoreLifecycleListener listener,
166: PreStoreNode next) {
167: this .listener = listener;
168: this .next = next;
169: }
170:
171: public PreStoreNode copy() {
172: return new PreStoreNode(listener, next == null ? null
173: : next.copy());
174: }
175: }
176:
177: private static class PostStoreNode {
178:
179: public PostStoreLifecycleListener listener;
180: public PostStoreNode next;
181:
182: public PostStoreNode(PostStoreLifecycleListener listener,
183: PostStoreNode next) {
184: this .listener = listener;
185: this .next = next;
186: }
187:
188: public PostStoreNode copy() {
189: return new PostStoreNode(listener, next == null ? null
190: : next.copy());
191: }
192: }
193:
194: private static class DeleteNode {
195:
196: public DeleteLifecycleListener listener;
197: public DeleteNode next;
198:
199: public DeleteNode(DeleteLifecycleListener listener,
200: DeleteNode next) {
201: this .listener = listener;
202: this .next = next;
203: }
204:
205: public DeleteNode copy() {
206: return new DeleteNode(listener, next == null ? null : next
207: .copy());
208: }
209: }
210:
211: }
|