001: package org.apache.ojb.broker.core;
002:
003: /* Copyright 2003-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import org.apache.ojb.broker.PBLifeCycleEvent;
019: import org.apache.ojb.broker.PBLifeCycleListener;
020: import org.apache.ojb.broker.PBListener;
021: import org.apache.ojb.broker.PBStateEvent;
022: import org.apache.ojb.broker.PBStateListener;
023: import org.apache.ojb.broker.PersistenceBrokerEvent;
024: import org.apache.ojb.broker.PersistenceBrokerException;
025: import org.apache.ojb.broker.PersistenceBrokerInternal;
026: import org.apache.ojb.broker.util.configuration.Configuration;
027: import org.apache.ojb.broker.util.configuration.ConfigurationException;
028: import org.apache.ojb.broker.util.logging.LoggerFactory;
029:
030: /**
031: * Abstract Implementation of the {@link org.apache.ojb.broker.PersistenceBroker}
032: * encapsulating the used PB-event/listener concept.
033: *
034: * @see org.apache.ojb.broker.PersistenceBroker
035: * @see org.apache.ojb.broker.PBLifeCycleListener
036: * @see org.apache.ojb.broker.PersistenceBrokerAware
037: * @see org.apache.ojb.broker.PBStateListener
038: *
039: * @author Created by Charles on 12-Sep-2002 08:04:47
040: * @author Armin Waibel
041: * @version $Id: PersistenceBrokerAbstractImpl.java,v 1.6.2.3 2005/12/21 22:25:00 tomdz Exp $
042: */
043: public abstract class PersistenceBrokerAbstractImpl implements
044: PersistenceBrokerInternal {
045: private static final PBStateListener[] NO_STATE_LISTENERS = new PBStateListener[0];
046: private static final PBLifeCycleListener[] NO_LIFECYCLE_LISTENERS = new PBLifeCycleListener[0];
047:
048: private boolean txCheck;
049:
050: /**
051: * Array containing all permanent {@link org.apache.ojb.broker.PBStateListener}
052: * instances.
053: */
054: private PBStateListener[] permanentStateListeners = NO_STATE_LISTENERS;
055:
056: /**
057: * Array containing all temporary {@link org.apache.ojb.broker.PBStateListener}
058: * instances.
059: */
060: private PBStateListener[] temporaryStateListeners = NO_STATE_LISTENERS;
061:
062: /**
063: * Array containing all permanent {@link org.apache.ojb.broker.PBLifeCycleListener}
064: * instances.
065: */
066: private PBLifeCycleListener[] permanentLifeCycleListeners = NO_LIFECYCLE_LISTENERS;
067:
068: /**
069: * Array containing all temporary {@link org.apache.ojb.broker.PBLifeCycleListener}
070: * instances.
071: */
072: private PBLifeCycleListener[] temporaryLifeCycleListeners = NO_LIFECYCLE_LISTENERS;
073:
074: /**
075: * Override if needed.
076: *
077: * @see org.apache.ojb.broker.util.configuration.Configurable#configure(Configuration)
078: */
079: public void configure(Configuration pConfig)
080: throws ConfigurationException {
081: txCheck = pConfig.getBoolean("TxCheck", false);
082: }
083:
084: /**
085: * Returns <em>true</em> if the development checks are enabled.
086: *
087: * @see #setTxCheck(boolean)
088: */
089: public boolean isTxCheck() {
090: return txCheck;
091: }
092:
093: /**
094: * This setting can be helpful during development if the PersistenceBroker transaction
095: * demarcation was used (this is true in most cases). If set 'true' on PB#store(...)
096: * and PB#delete(...) methods calls OJB check for active PB-tx and if no active tx is
097: * found a error is logged. This can help to avoid store/delete calls without a running
098: * PB-tx while development. Default setting is 'false'.
099: * <p/>
100: * <strong>Note:</strong> When using OJB in a managed
101: * environment <em>without</em> OJB-caching, it's valid to use store/delete
102: * calls without a running PB-tx.
103: *
104: * @param txCheck Set <em>true</em> to enable the checks
105: */
106: public void setTxCheck(boolean txCheck) {
107: this .txCheck = txCheck;
108: }
109:
110: /**
111: * @see org.apache.ojb.broker.PersistenceBroker#addListener(PBListener listener)
112: */
113: public void addListener(PBListener listener)
114: throws PersistenceBrokerException {
115: addListener(listener, false);
116: }
117:
118: /**
119: * @see org.apache.ojb.broker.PersistenceBroker#addListener(PBListener listener, boolean permanent)
120: */
121: public void addListener(PBListener listener, boolean permanent)
122: throws PersistenceBrokerException {
123: if (listener instanceof PBStateListener) {
124: if (permanent) {
125: if (!contains(permanentStateListeners, listener)) {
126: PBStateListener[] newListeners = new PBStateListener[permanentStateListeners.length + 1];
127: System.arraycopy(permanentStateListeners, 0,
128: newListeners, 0,
129: permanentStateListeners.length);
130: newListeners[newListeners.length - 1] = (PBStateListener) listener;
131: permanentStateListeners = newListeners;
132: }
133: } else {
134: if (!contains(temporaryStateListeners, listener)) {
135: PBStateListener[] newListeners = new PBStateListener[temporaryStateListeners.length + 1];
136: System.arraycopy(temporaryStateListeners, 0,
137: newListeners, 0,
138: temporaryStateListeners.length);
139: newListeners[newListeners.length - 1] = (PBStateListener) listener;
140: temporaryStateListeners = newListeners;
141: }
142: }
143: }
144:
145: if (listener instanceof PBLifeCycleListener) {
146: if (permanent) {
147: if (!contains(permanentLifeCycleListeners, listener)) {
148: PBLifeCycleListener[] newListeners = new PBLifeCycleListener[permanentLifeCycleListeners.length + 1];
149: System.arraycopy(permanentLifeCycleListeners, 0,
150: newListeners, 0,
151: permanentLifeCycleListeners.length);
152: newListeners[newListeners.length - 1] = (PBLifeCycleListener) listener;
153: permanentLifeCycleListeners = newListeners;
154: }
155: } else {
156: if (!contains(temporaryLifeCycleListeners, listener)) {
157: PBLifeCycleListener[] newListeners = new PBLifeCycleListener[temporaryLifeCycleListeners.length + 1];
158: System.arraycopy(temporaryLifeCycleListeners, 0,
159: newListeners, 0,
160: temporaryLifeCycleListeners.length);
161: newListeners[newListeners.length - 1] = (PBLifeCycleListener) listener;
162: temporaryLifeCycleListeners = newListeners;
163: }
164: }
165: }
166: }
167:
168: /**
169: * @see org.apache.ojb.broker.PersistenceBroker#removeListener(PBListener listener)
170: */
171: public void removeListener(PBListener listener)
172: throws PersistenceBrokerException {
173: if (listener instanceof PBStateListener) {
174: if (contains(permanentStateListeners, listener)) {
175: PBStateListener[] newListeners = new PBStateListener[permanentStateListeners.length - 1];
176: int pos = 0;
177:
178: for (int i = 0; i < permanentStateListeners.length; i++) {
179: if (permanentStateListeners[i] != listener) {
180: newListeners[pos++] = permanentStateListeners[i];
181: }
182: }
183: permanentStateListeners = newListeners;
184: }
185:
186: if (contains(temporaryStateListeners, listener)) {
187: PBStateListener[] newListeners = new PBStateListener[temporaryStateListeners.length - 1];
188: int pos = 0;
189:
190: for (int i = 0; i < temporaryStateListeners.length; i++) {
191: if (temporaryStateListeners[i] != listener) {
192: newListeners[pos++] = temporaryStateListeners[i];
193: }
194: }
195: temporaryStateListeners = newListeners;
196: }
197: }
198:
199: if (listener instanceof PBLifeCycleListener) {
200: if (contains(permanentLifeCycleListeners, listener)) {
201: PBLifeCycleListener[] newListeners = new PBLifeCycleListener[permanentLifeCycleListeners.length - 1];
202: int pos = 0;
203:
204: for (int i = 0; i < permanentLifeCycleListeners.length; i++) {
205: if (permanentLifeCycleListeners[i] != listener) {
206: newListeners[pos++] = permanentLifeCycleListeners[i];
207: }
208: }
209: permanentLifeCycleListeners = newListeners;
210: }
211:
212: if (contains(temporaryLifeCycleListeners, listener)) {
213: PBLifeCycleListener[] newListeners = new PBLifeCycleListener[temporaryLifeCycleListeners.length - 1];
214: int pos = 0;
215:
216: for (int i = 0; i < temporaryLifeCycleListeners.length; i++) {
217: if (temporaryLifeCycleListeners[i] != listener) {
218: newListeners[pos++] = temporaryLifeCycleListeners[i];
219: }
220: }
221: temporaryLifeCycleListeners = newListeners;
222: }
223: }
224: }
225:
226: protected boolean contains(PBListener[] listeners,
227: PBListener listener) {
228: for (int i = listeners.length - 1; i >= 0; i--) {
229: if (listeners[i] == listener)
230: return true;
231: }
232:
233: return false;
234: }
235:
236: /**
237: * @see org.apache.ojb.broker.PersistenceBroker#removeAllListeners(boolean)
238: */
239: public void removeAllListeners(boolean permanent)
240: throws PersistenceBrokerException {
241: if (permanent) {
242: // remove permanent listeners as well
243: permanentStateListeners = NO_STATE_LISTENERS;
244: permanentLifeCycleListeners = NO_LIFECYCLE_LISTENERS;
245: }
246:
247: temporaryStateListeners = NO_STATE_LISTENERS;
248: temporaryLifeCycleListeners = NO_LIFECYCLE_LISTENERS;
249: }
250:
251: /**
252: * @see org.apache.ojb.broker.PersistenceBroker#removeAllListeners()
253: */
254: public void removeAllListeners() throws PersistenceBrokerException {
255: removeAllListeners(false);
256: }
257:
258: public void fireBrokerEvent(PersistenceBrokerEvent event) {
259: if (event instanceof PBLifeCycleEvent) {
260: fireBrokerEvent((PBLifeCycleEvent) event);
261: } else if (event instanceof PBStateEvent) {
262: fireBrokerEvent((PBStateEvent) event);
263: } else {
264: LoggerFactory
265: .getDefaultLogger()
266: .error(
267: PersistenceBrokerAbstractImpl.class
268: .getName()
269: + ": Unkown PersistenceBrokerEvent was fired "
270: + event);
271: }
272: }
273:
274: public void fireBrokerEvent(PBLifeCycleEvent event) {
275: if (event.getPersitenceBrokerAware() != null) {
276: // first we do the persistent object callback
277: performCallBack(event);
278: }
279:
280: // copy array references so they can't change in the middle of iteration
281: PBLifeCycleListener[] permanent = permanentLifeCycleListeners;
282: PBLifeCycleListener[] temporary = temporaryLifeCycleListeners;
283:
284: // now we notify the listeners
285: for (int i = permanent.length - 1; i >= 0; i--) {
286: notifiyObjectLifeCycleListener(permanent[i], event);
287: }
288:
289: for (int i = temporary.length - 1; i >= 0; i--) {
290: notifiyObjectLifeCycleListener(temporary[i], event);
291: }
292: }
293:
294: public void fireBrokerEvent(PBStateEvent event) {
295: // copy array references so they can't change in the middle of iteration
296: PBStateListener[] permanent = permanentStateListeners;
297: PBStateListener[] temporary = temporaryStateListeners;
298:
299: // now we notify the listeners
300: for (int i = permanent.length - 1; i >= 0; i--) {
301: notifiyStateListener(permanent[i], event);
302: }
303:
304: for (int i = temporary.length - 1; i >= 0; i--) {
305: notifiyStateListener(temporary[i], event);
306: }
307: }
308:
309: private void performCallBack(PBLifeCycleEvent event) {
310: // Check for null
311: if (event.getPersitenceBrokerAware() == null)
312: return;
313: switch (event.getEventType().typeId()) {
314: case PBLifeCycleEvent.TYPE_AFTER_LOOKUP:
315: event.getPersitenceBrokerAware().afterLookup(
316: event.getTriggeringBroker());
317: break;
318: case PBLifeCycleEvent.TYPE_BEFORE_UPDATE:
319: event.getPersitenceBrokerAware().beforeUpdate(
320: event.getTriggeringBroker());
321: break;
322: case PBLifeCycleEvent.TYPE_AFTER_UPDATE:
323: event.getPersitenceBrokerAware().afterUpdate(
324: event.getTriggeringBroker());
325: break;
326: case PBLifeCycleEvent.TYPE_BEFORE_INSERT:
327: event.getPersitenceBrokerAware().beforeInsert(
328: event.getTriggeringBroker());
329: break;
330: case PBLifeCycleEvent.TYPE_AFTER_INSERT:
331: event.getPersitenceBrokerAware().afterInsert(
332: event.getTriggeringBroker());
333: break;
334: case PBLifeCycleEvent.TYPE_BEFORE_DELETE:
335: event.getPersitenceBrokerAware().beforeDelete(
336: event.getTriggeringBroker());
337: break;
338: case PBLifeCycleEvent.TYPE_AFTER_DELETE:
339: event.getPersitenceBrokerAware().afterDelete(
340: event.getTriggeringBroker());
341: break;
342: }
343: }
344:
345: private void notifiyStateListener(PBStateListener listener,
346: PBStateEvent stateEvent) {
347: switch (stateEvent.getEventType().typeId()) {
348: case PBStateEvent.KEY_BEFORE_COMMIT:
349: listener.beforeCommit(stateEvent);
350: break;
351: case PBStateEvent.KEY_AFTER_COMMIT:
352: listener.afterCommit(stateEvent);
353: break;
354: case PBStateEvent.KEY_BEFORE_BEGIN:
355: listener.beforeBegin(stateEvent);
356: break;
357: case PBStateEvent.KEY_AFTER_BEGIN:
358: listener.afterBegin(stateEvent);
359: break;
360: case PBStateEvent.KEY_BEFORE_CLOSE:
361: listener.beforeClose(stateEvent);
362: break;
363: case PBStateEvent.KEY_AFTER_OPEN:
364: listener.afterOpen(stateEvent);
365: break;
366: case PBStateEvent.KEY_AFTER_ROLLBACK:
367: listener.afterRollback(stateEvent);
368: break;
369: case PBStateEvent.KEY_BEFORE_ROLLBACK:
370: listener.beforeRollback(stateEvent);
371: break;
372: }
373: }
374:
375: private void notifiyObjectLifeCycleListener(
376: PBLifeCycleListener listener, PBLifeCycleEvent lifeEvent) {
377: switch (lifeEvent.getEventType().typeId()) {
378: case PBLifeCycleEvent.TYPE_AFTER_LOOKUP:
379: listener.afterLookup(lifeEvent);
380: break;
381: case PBLifeCycleEvent.TYPE_BEFORE_UPDATE:
382: listener.beforeUpdate(lifeEvent);
383: break;
384: case PBLifeCycleEvent.TYPE_AFTER_UPDATE:
385: listener.afterUpdate(lifeEvent);
386: break;
387: case PBLifeCycleEvent.TYPE_BEFORE_INSERT:
388: listener.beforeInsert(lifeEvent);
389: break;
390: case PBLifeCycleEvent.TYPE_AFTER_INSERT:
391: listener.afterInsert(lifeEvent);
392: break;
393: case PBLifeCycleEvent.TYPE_BEFORE_DELETE:
394: listener.beforeDelete(lifeEvent);
395: break;
396: case PBLifeCycleEvent.TYPE_AFTER_DELETE:
397: listener.afterDelete(lifeEvent);
398: break;
399: }
400: }
401:
402: /*
403: arminw:
404: get the PB state event here, this helps to
405: avoid object instantiation for any event call
406: */
407: protected final PBStateEvent AFTER_OPEN_EVENT = new PBStateEvent(
408: this , PBStateEvent.Type.AFTER_OPEN);
409: protected final PBStateEvent AFTER_BEGIN_EVENT = new PBStateEvent(
410: this , PBStateEvent.Type.AFTER_BEGIN);
411: protected final PBStateEvent AFTER_COMMIT_EVENT = new PBStateEvent(
412: this , PBStateEvent.Type.AFTER_COMMIT);
413: protected final PBStateEvent AFTER_ROLLBACK_EVENT = new PBStateEvent(
414: this , PBStateEvent.Type.AFTER_ROLLBACK);
415: protected final PBStateEvent BEFORE_BEGIN_EVENT = new PBStateEvent(
416: this , PBStateEvent.Type.BEFORE_BEGIN);
417: protected final PBStateEvent BEFORE_COMMIT_EVENT = new PBStateEvent(
418: this , PBStateEvent.Type.BEFORE_COMMIT);
419: protected final PBStateEvent BEFORE_ROLLBACK_EVENT = new PBStateEvent(
420: this , PBStateEvent.Type.BEFORE_ROLLBACK);
421: protected final PBStateEvent BEFORE_CLOSE_EVENT = new PBStateEvent(
422: this , PBStateEvent.Type.BEFORE_CLOSE);
423:
424: /*
425: arminw:
426: here we could get the PB state event, this helps to
427: avoid object instantiation on every event
428: NOTE: It's a little critical, because caller shouldn't forget
429: to set the target object using #setTargetObject(...) method.
430: This means that we use the same event object with changed
431: fields.
432: TODO: find a better solution (and performant)
433: */
434: protected PBLifeCycleEvent BEFORE_STORE_EVENT = new PBLifeCycleEvent(
435: this , PBLifeCycleEvent.Type.BEFORE_INSERT);
436: protected PBLifeCycleEvent AFTER_STORE_EVENT = new PBLifeCycleEvent(
437: this , PBLifeCycleEvent.Type.AFTER_INSERT);
438: protected PBLifeCycleEvent BEFORE_DELETE_EVENT = new PBLifeCycleEvent(
439: this , PBLifeCycleEvent.Type.BEFORE_DELETE);
440: protected PBLifeCycleEvent AFTER_DELETE_EVENT = new PBLifeCycleEvent(
441: this , PBLifeCycleEvent.Type.AFTER_DELETE);
442: protected PBLifeCycleEvent AFTER_LOOKUP_EVENT = new PBLifeCycleEvent(
443: this , PBLifeCycleEvent.Type.AFTER_LOOKUP);
444: protected PBLifeCycleEvent BEFORE_UPDATE_EVENT = new PBLifeCycleEvent(
445: this , PBLifeCycleEvent.Type.BEFORE_UPDATE);
446: protected PBLifeCycleEvent AFTER_UPDATE_EVENT = new PBLifeCycleEvent(
447: this, PBLifeCycleEvent.Type.AFTER_UPDATE);
448: }
|