1 package org.apache.ojb.odmg;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import javax.transaction.Status;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Enumeration;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.apache.commons.lang.SystemUtils;
27 import org.apache.ojb.broker.Identity;
28 import org.apache.ojb.broker.OJBRuntimeException;
29 import org.apache.ojb.broker.PBFactoryException;
30 import org.apache.ojb.broker.PersistenceBroker;
31 import org.apache.ojb.broker.PersistenceBrokerException;
32 import org.apache.ojb.broker.PersistenceBrokerInternal;
33 import org.apache.ojb.broker.core.PersistenceBrokerFactoryFactory;
34 import org.apache.ojb.broker.core.proxy.CollectionProxy;
35 import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
36 import org.apache.ojb.broker.core.proxy.CollectionProxyListener;
37 import org.apache.ojb.broker.core.proxy.IndirectionHandler;
38 import org.apache.ojb.broker.core.proxy.MaterializationListener;
39 import org.apache.ojb.broker.core.proxy.ProxyHelper;
40 import org.apache.ojb.broker.metadata.ClassDescriptor;
41 import org.apache.ojb.broker.metadata.CollectionDescriptor;
42 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
43 import org.apache.ojb.broker.util.BrokerHelper;
44 import org.apache.ojb.broker.util.GUID;
45 import org.apache.ojb.broker.util.configuration.Configurable;
46 import org.apache.ojb.broker.util.configuration.Configuration;
47 import org.apache.ojb.broker.util.configuration.ConfigurationException;
48 import org.apache.ojb.broker.util.logging.Logger;
49 import org.apache.ojb.broker.util.logging.LoggerFactory;
50 import org.apache.ojb.odmg.locking.LockManager;
51 import org.odmg.DatabaseClosedException;
52 import org.odmg.LockNotGrantedException;
53 import org.odmg.ODMGRuntimeException;
54 import org.odmg.Transaction;
55 import org.odmg.TransactionAbortedException;
56 import org.odmg.TransactionNotInProgressException;
57
58
59
60
61
62
63
64
65
66
67
68
69 public class TransactionImpl
70 implements Transaction, MaterializationListener, Configurable, CollectionProxyListener, TransactionExt
71 {
72 private Logger log = LoggerFactory.getLogger(TransactionImpl.class);
73 private boolean impliciteWriteLocks;
74 private boolean implicitLocking;
75 private boolean ordering;
76
77 private String txGUID;
78 protected PersistenceBrokerInternal broker = null;
79 private ArrayList registrationList = new ArrayList();
80 private ImplementationImpl implementation;
81 private NamedRootsMap namedRootsMap;
82
83
84
85
86
87
88 private int txStatus = Status.STATUS_NO_TRANSACTION;
89
90
91
92
93
94 protected ObjectEnvelopeTable objectEnvelopeTable = null;
95
96
97
98
99 private DatabaseImpl curDB;
100
101
102
103
104
105 private ArrayList registeredIndirectionHandlers = new ArrayList();
106
107
108
109
110
111 private ArrayList registeredCollectionProxies = new ArrayList();
112
113
114
115
116
117 private ArrayList unmaterializedLocks = new ArrayList();
118
119
120
121
122
123 public TransactionImpl(ImplementationImpl implementation)
124 {
125 this.implementation = implementation;
126 this.impliciteWriteLocks = implementation.isImpliciteWriteLocks();
127 this.implicitLocking = implementation.isImplicitLocking();
128 this.ordering = implementation.isOrdering();
129
130
131
132 txGUID = new GUID().toString();
133 curDB = implementation.getCurrentDatabase();
134 namedRootsMap = new NamedRootsMap(this);
135 }
136
137 public ImplementationImpl getImplementation()
138 {
139 return implementation;
140 }
141
142 public NamedRootsMap getNamedRootsMap()
143 {
144 return namedRootsMap;
145 }
146
147
148
149
150 public DatabaseImpl getAssociatedDatabase()
151 {
152 return this.curDB;
153 }
154
155 protected int getStatus()
156 {
157 return txStatus;
158 }
159
160 protected void setStatus(int status)
161 {
162 this.txStatus = status;
163 }
164
165 private void checkForDB()
166 {
167 if (curDB == null || !curDB.isOpen())
168 {
169 log.error("Transaction without a associated open Database.");
170 throw new TransactionAbortedExceptionOJB(
171 "No open database found. Open the database before handling transactions");
172 }
173 }
174
175
176
177
178
179
180
181 public boolean isOpen()
182 {
183 return (getStatus() == Status.STATUS_ACTIVE ||
184 getStatus() == Status.STATUS_MARKED_ROLLBACK ||
185 getStatus() == Status.STATUS_PREPARED ||
186 getStatus() == Status.STATUS_PREPARING ||
187 getStatus() == Status.STATUS_COMMITTING);
188 }
189
190 private void checkOpen()
191 {
192 if (!isOpen())
193 {
194 throw new TransactionNotInProgressException(
195 "Transaction was not open, call tx.begin() before perform action, current status is: " +
196 TxUtil.getStatusString(getStatus()));
197 }
198 }
199
200
201
202
203
204
205
206 public void join()
207 {
208 checkOpen();
209 implementation.getTxManager().deregisterTx(this);
210 implementation.getTxManager().registerTx(this);
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224 public void lock(Object obj, int lockMode) throws LockNotGrantedException
225 {
226 if (log.isDebugEnabled()) log.debug("lock object was called on tx " + this + ", object is " + obj.toString());
227 checkOpen();
228 RuntimeObject rtObject = new RuntimeObject(obj, this);
229 lockAndRegister(rtObject, lockMode, isImplicitLocking(), getRegistrationList());
230
231 }
232
233
234
235
236 public ArrayList getRegistrationList()
237 {
238 clearRegistrationList();
239 return registrationList;
240 }
241
242
243
244
245 public void clearRegistrationList()
246 {
247 registrationList.clear();
248 }
249
250
251
252
253
254 public void lockAndRegister(RuntimeObject rtObject, int lockMode, List registeredObjects)
255 {
256 lockAndRegister(rtObject, lockMode, isImplicitLocking(), registeredObjects);
257 }
258
259
260
261
262
263 public synchronized void lockAndRegister(RuntimeObject rtObject, int lockMode, boolean cascade, List registeredObjects)
264 {
265 if(log.isDebugEnabled()) log.debug("Lock and register called for " + rtObject.getIdentity());
266
267
268 if(!registeredObjects.contains(rtObject.getIdentity()))
269 {
270 if(cascade)
271 {
272
273
274 registeredObjects.add(rtObject.getIdentity());
275
276
277
278
279 lockAndRegisterReferences(rtObject.getCld(), rtObject.getObjMaterialized(), lockMode, registeredObjects);
280 }
281 try
282 {
283
284
285 if(!rtObject.isNew())
286 {
287 doSingleLock(rtObject.getCld(), rtObject.getObj(), rtObject.getIdentity(), lockMode);
288 }
289
290 doSingleRegister(rtObject, lockMode);
291 }
292 catch (Throwable t)
293 {
294
295
296
297 implementation.getLockManager().releaseLock(this, rtObject.getIdentity(), rtObject.getObj());
298 if(t instanceof LockNotGrantedException)
299 {
300 throw (LockNotGrantedException) t;
301 }
302 else
303 {
304 log.error("Unexpected failure while locking", t);
305 throw new LockNotGrantedException("Locking failed for "
306 + rtObject.getIdentity()+ ", nested exception is: [" + t.getClass().getName()
307 + ": " + t.getMessage() + "]");
308 }
309 }
310 if(cascade)
311 {
312
313
314
315 lockAndRegisterCollections(rtObject.getCld(), rtObject.getObjMaterialized(), lockMode, registeredObjects);
316 }
317 }
318 }
319
320
321
322
323
324
325
326
327
328
329
330
331
332 void doSingleLock(ClassDescriptor cld, Object obj, Identity oid, int lockMode) throws LockNotGrantedException
333 {
334 LockManager lm = implementation.getLockManager();
335 if (cld.isAcceptLocks())
336 {
337 if (lockMode == Transaction.READ)
338 {
339 if (log.isDebugEnabled()) log.debug("Do READ lock on object: " + oid);
340 if(!lm.readLock(this, oid, obj))
341 {
342 throw new LockNotGrantedException("Can not lock for READ: " + oid);
343 }
344 }
345 else if (lockMode == Transaction.WRITE)
346 {
347 if (log.isDebugEnabled()) log.debug("Do WRITE lock on object: " + oid);
348 if(!lm.writeLock(this, oid, obj))
349 {
350 throw new LockNotGrantedException("Can not lock for WRITE: " + oid);
351 }
352 }
353 else if (lockMode == Transaction.UPGRADE)
354 {
355 if (log.isDebugEnabled()) log.debug("Do UPGRADE lock on object: " + oid);
356 if(!lm.upgradeLock(this, oid, obj))
357 {
358 throw new LockNotGrantedException("Can not lock for UPGRADE: " + oid);
359 }
360 }
361 }
362 else
363 {
364 if (log.isDebugEnabled())
365 {
366 log.debug("Class '" + cld.getClassNameOfObject() + "' doesn't accept locks" +
367 " (accept-locks=false) when implicite locked, so OJB skip this object: " + oid);
368 }
369 }
370 }
371
372
373
374
375
376 public void leave()
377 {
378 checkOpen();
379 implementation.getTxManager().deregisterTx(this);
380 }
381
382
383
384
385
386
387 protected synchronized void doWriteObjects(boolean isFlush) throws TransactionAbortedException, LockNotGrantedException
388 {
389
390
391
392
393 if (!getBroker().isInTransaction())
394 {
395 if (log.isDebugEnabled()) log.debug("call beginTransaction() on PB instance");
396 broker.beginTransaction();
397 }
398
399
400 performTransactionAwareBeforeCommit();
401
402
403 objectEnvelopeTable.writeObjects(isFlush);
404
405 namedRootsMap.performDeletion();
406 namedRootsMap.performInsert();
407 namedRootsMap.afterWriteCleanup();
408 }
409
410
411
412
413
414
415 protected synchronized void doAbort()
416 {
417
418 performTransactionAwareBeforeRollback();
419
420
421 objectEnvelopeTable.rollback();
422
423
424 performTransactionAwareAfterRollback();
425 }
426
427
428
429
430 protected synchronized void doClose()
431 {
432 try
433 {
434 LockManager lm = getImplementation().getLockManager();
435 Enumeration en = objectEnvelopeTable.elements();
436 while (en.hasMoreElements())
437 {
438 ObjectEnvelope oe = (ObjectEnvelope) en.nextElement();
439 lm.releaseLock(this, oe.getIdentity(), oe.getObject());
440 }
441
442
443 for (Iterator it = unmaterializedLocks.iterator(); it.hasNext();)
444 {
445 lm.releaseLock(this, it.next());
446 }
447
448
449 unRegisterFromAllIndirectionHandlers();
450 unRegisterFromAllCollectionProxies();
451 }
452 finally
453 {
454
455
456
457 if (log.isDebugEnabled())
458 log.debug("Close Transaction and release current PB " + broker + " on tx " + this);
459
460
461 implementation.getTxManager().deregisterTx(this);
462
463 refresh();
464 }
465 }
466
467
468
469
470 protected void refresh()
471 {
472 if (log.isDebugEnabled())
473 log.debug("Refresh this transaction for reuse: " + this);
474 try
475 {
476
477 objectEnvelopeTable.refresh();
478 }
479 catch (Exception e)
480 {
481 if (log.isDebugEnabled())
482 {
483 log.debug("error closing object envelope table : " + e.getMessage());
484 e.printStackTrace();
485 }
486 }
487 cleanupBroker();
488
489
490
491 broker = null;
492 clearRegistrationList();
493 unmaterializedLocks.clear();
494 txStatus = Status.STATUS_NO_TRANSACTION;
495 }
496
497
498
499
500
501
502
503
504 public void checkpoint()
505 {
506 if (log.isDebugEnabled()) log.debug("Checkpoint was called, commit changes hold locks on tx " + this);
507 try
508 {
509 checkOpen();
510 doWriteObjects(true);
511
512 if (hasBroker() && broker.isInTransaction()) broker.commitTransaction();
513 }
514 catch (Throwable t)
515 {
516 log.error("Checkpoint call failed, do abort transaction", t);
517 txStatus = Status.STATUS_MARKED_ROLLBACK;
518 abort();
519 if(!(t instanceof ODMGRuntimeException))
520 {
521 throw new TransactionAbortedExceptionOJB("Can't tx.checkpoint() objects: " + t.getMessage(), t);
522 }
523 else
524 {
525 throw (ODMGRuntimeException) t;
526 }
527 }
528 }
529
530
531
532
533 public void flush()
534 {
535 if (log.isDebugEnabled())
536 {
537 log.debug("Flush was called - write changes to database, do not commit, hold locks on tx " + this);
538 }
539
540 try
541 {
542 checkOpen();
543 doWriteObjects(true);
544 }
545 catch (Throwable t)
546 {
547 log.error("Calling method 'tx.flush()' failed", t);
548 txStatus = Status.STATUS_MARKED_ROLLBACK;
549 abort();
550 if(!(t instanceof ODMGRuntimeException))
551 {
552 throw new TransactionAbortedExceptionOJB("Can't tx.flush() objects: " + t.getMessage(), t);
553 }
554 else
555 {
556 throw (ODMGRuntimeException) t;
557 }
558 }
559 }
560
561
562
563
564 public void markDelete(Object anObject)
565 {
566 ObjectEnvelope otw = objectEnvelopeTable.get(anObject, false);
567
568
569 otw.setModificationState(otw.getModificationState().markDelete());
570 }
571
572 public void deletePersistent(RuntimeObject rt)
573 {
574
575
576
577
578 if(rt.isProxy())
579 {
580 Object realObj = rt.getHandler().getRealSubject();
581 rt = new RuntimeObject(realObj, rt.getIdentity(), this, false);
582 }
583 lockAndRegister(rt, Transaction.WRITE, getRegistrationList());
584 ObjectEnvelope oe = objectEnvelopeTable.getByIdentity(rt.getIdentity());
585
586
587 oe.refreshObjectIfNeeded(rt.getObj());
588 oe.setModificationState(oe.getModificationState().markDelete());
589 }
590
591
592
593
594 public void markDirty(Object anObject)
595 {
596 ObjectEnvelope otw = objectEnvelopeTable.get(anObject, false);
597 otw.refreshObjectIfNeeded(anObject);
598 otw.setModificationState(otw.getModificationState().markDirty());
599 }
600
601 void markDirty(RuntimeObject rt)
602 {
603 ObjectEnvelope otw = objectEnvelopeTable.get(rt.getIdentity(), rt.getObj(), rt.isNew());
604 otw.refreshObjectIfNeeded(rt.getObj());
605 otw.setModificationState(otw.getModificationState().markDirty());
606 }
607
608 void markPersistent(RuntimeObject rtObj)
609 {
610 ObjectEnvelope oe = objectEnvelopeTable.getByIdentity(rtObj.getIdentity());
611 if(oe == null)
612 {
613 oe = objectEnvelopeTable.get(rtObj.getIdentity(), rtObj.getObj(), rtObj.isNew());
614 }
615 if(oe.needsDelete())
616 {
617 oe.setModificationState(oe.getModificationState().markNew());
618 }
619 else
620 {
621 oe.setModificationState(oe.getModificationState().markDirty());
622 }
623 oe.refreshObjectIfNeeded(rtObj.getObj());
624 }
625
626 void makePersistent(RuntimeObject rt)
627 {
628 try
629 {
630 lockAndRegister(rt, Transaction.WRITE, getRegistrationList());
631 markPersistent(rt);
632 }
633 catch (org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException ex)
634 {
635 log.error("Can't persist object: " + rt.getIdentity(), ex);
636 throw new org.odmg.ClassNotPersistenceCapableException(ex.getMessage());
637 }
638 }
639
640
641
642
643 public boolean isDeleted(Identity id)
644 {
645 ObjectEnvelope envelope = objectEnvelopeTable.getByIdentity(id);
646 return (envelope != null && envelope.needsDelete());
647 }
648
649
650
651
652
653
654
655
656
657
658
659 public boolean tryLock(Object obj, int lockMode)
660 {
661 if (log.isDebugEnabled()) log.debug("Try to lock object was called on tx " + this);
662 checkOpen();
663 try
664 {
665 lock(obj, lockMode);
666 return true;
667 }
668 catch (LockNotGrantedException ex)
669 {
670 return false;
671 }
672 }
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693 public void commit()
694 {
695 checkOpen();
696 try
697 {
698 prepareCommit();
699 checkForCommit();
700
701 txStatus = Status.STATUS_COMMITTING;
702 if (log.isDebugEnabled()) log.debug("Commit transaction " + this);
703
704 if(hasBroker()) getBroker().commitTransaction();
705
706
707 performTransactionAwareAfterCommit();
708
709 doClose();
710 txStatus = Status.STATUS_COMMITTED;
711 }
712 catch(Exception ex)
713 {
714 log.error("Error while commit objects, do abort tx " + this + ", " + ex.getMessage(), ex);
715 txStatus = Status.STATUS_MARKED_ROLLBACK;
716 abort();
717 if(!(ex instanceof ODMGRuntimeException))
718 {
719 throw new TransactionAbortedExceptionOJB("Can't commit objects: " + ex.getMessage(), ex);
720 }
721 else
722 {
723 throw (ODMGRuntimeException) ex;
724 }
725 }
726 }
727
728 protected void checkForCommit()
729 {
730
731 if (txStatus == Status.STATUS_MARKED_ROLLBACK)
732 throw new TransactionAbortedExceptionOJB("Illegal tx-status: tx is already markedRollback");
733
734 if (txStatus != Status.STATUS_PREPARED)
735 throw new IllegalStateException("Illegal tx-status: Do prepare commit before commit");
736 }
737
738
739
740
741
742
743
744
745
746
747
748
749 protected void prepareCommit() throws TransactionAbortedException, LockNotGrantedException
750 {
751 if (txStatus == Status.STATUS_MARKED_ROLLBACK)
752 {
753 throw new TransactionAbortedExceptionOJB("Prepare Transaction: tx already marked for rollback");
754 }
755 if (txStatus != Status.STATUS_ACTIVE)
756 {
757 throw new IllegalStateException("Prepare Transaction: tx status is not 'active', status is " + TxUtil.getStatusString(txStatus));
758 }
759 try
760 {
761 txStatus = Status.STATUS_PREPARING;
762 doWriteObjects(false);
763 txStatus = Status.STATUS_PREPARED;
764 }
765 catch (RuntimeException e)
766 {
767 log.error("Could not prepare for commit", e);
768 txStatus = Status.STATUS_MARKED_ROLLBACK;
769 throw e;
770 }
771 }
772
773
774
775
776
777
778 public void abort()
779 {
780
781
782
783 if (txStatus == Status.STATUS_NO_TRANSACTION
784 || txStatus == Status.STATUS_UNKNOWN
785 || txStatus == Status.STATUS_ROLLEDBACK)
786 {
787 log.info("Nothing to abort, tx is not active - status is " + TxUtil.getStatusString(txStatus));
788 return;
789 }
790
791 if (txStatus != Status.STATUS_ACTIVE && txStatus != Status.STATUS_PREPARED &&
792 txStatus != Status.STATUS_MARKED_ROLLBACK)
793 {
794 throw new IllegalStateException("Illegal state for abort call, state was '" + TxUtil.getStatusString(txStatus) + "'");
795 }
796 if(log.isEnabledFor(Logger.INFO))
797 {
798 log.info("Abort transaction was called on tx " + this);
799 }
800 try
801 {
802 try
803 {
804 doAbort();
805 }
806 catch(Exception e)
807 {
808 log.error("Error while abort transaction, will be skipped", e);
809 }
810
811
812 this.implementation.getTxManager().abortExternalTx(this);
813
814 try
815 {
816 if(hasBroker() && getBroker().isInTransaction())
817 {
818 getBroker().abortTransaction();
819 }
820 }
821 catch(Exception e)
822 {
823 log.error("Error while do abort used broker instance, will be skipped", e);
824 }
825 }
826 finally
827 {
828 txStatus = Status.STATUS_ROLLEDBACK;
829
830 doClose();
831 }
832 }
833
834
835
836
837
838
839
840
841
842
843
844 public synchronized void begin()
845 {
846 checkForBegin();
847 if (log.isDebugEnabled()) log.debug("Begin transaction was called on tx " + this);
848
849 objectEnvelopeTable = new ObjectEnvelopeTable(this);
850
851 implementation.getTxManager().registerTx(this);
852
853 txStatus = Status.STATUS_ACTIVE;
854 }
855
856 protected void checkForBegin()
857 {
858
859
860
861 if ((curDB == null) || !curDB.isOpen())
862 {
863 throw new DatabaseClosedException("Database is not open. Must have an open DB to begin the Tx.");
864 }
865 if (isOpen())
866 {
867 log.error("Transaction is already open");
868 throw new org.odmg.TransactionInProgressException("Impossible to call begin on already opened tx");
869 }
870 }
871
872 public String getGUID()
873 {
874 return txGUID;
875 }
876
877
878
879
880
881
882
883
884 public Object getObjectByIdentity(Identity id)
885 throws PersistenceBrokerException
886 {
887 checkOpen();
888 ObjectEnvelope envelope = objectEnvelopeTable.getByIdentity(id);
889 if (envelope != null)
890 {
891 return (envelope.needsDelete() ? null : envelope.getObject());
892 }
893 else
894 {
895 return getBroker().getObjectByIdentity(id);
896 }
897 }
898
899
900
901
902
903 void doSingleRegister(RuntimeObject rtObject, int lockMode)
904 throws LockNotGrantedException, PersistenceBrokerException
905 {
906 if(log.isDebugEnabled()) log.debug("Register object " + rtObject.getIdentity());
907 Object objectToRegister = rtObject.getObj();
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925 if(rtObject.isProxy())
926 {
927 IndirectionHandler handler = rtObject.getHandler();
928 if(handler == null)
929 {
930 throw new OJBRuntimeException("Unexpected error, expect an proxy object as indicated: " + rtObject);
931 }
932 if (handler.alreadyMaterialized())
933 {
934 objectToRegister = handler.getRealSubject();
935 }
936 else
937 {
938 registerToIndirectionHandler(handler);
939 registerUnmaterializedLocks(rtObject.getObj());
940
941 objectToRegister = null;
942 }
943 }
944
945 if (objectToRegister != null)
946 {
947 ObjectEnvelope envelope = objectEnvelopeTable.getByIdentity(rtObject.getIdentity());
948
949
950 if ((envelope == null))
951 {
952
953 envelope = objectEnvelopeTable.get(rtObject.getIdentity(), objectToRegister, rtObject.isNew());
954 }
955 else
956 {
957
958
959
960
961
962
963 envelope.refreshObjectIfNeeded(objectToRegister);
964 }
965
966
967
968
969
970 if(lockMode == Transaction.WRITE)
971 {
972
973 envelope.setWriteLocked(true);
974 }
975 }
976 }
977
978
979
980
981
982
983 private void lockAndRegisterReferences(ClassDescriptor cld, Object sourceObject, int lockMode, List registeredObjects) throws LockNotGrantedException
984 {
985 if (implicitLocking)
986 {
987 Iterator i = cld.getObjectReferenceDescriptors(true).iterator();
988 while (i.hasNext())
989 {
990 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next();
991 Object refObj = rds.getPersistentField().get(sourceObject);
992 if (refObj != null)
993 {
994 boolean isProxy = ProxyHelper.isProxy(refObj);
995 RuntimeObject rt = isProxy ? new RuntimeObject(refObj, this, false) : new RuntimeObject(refObj, this);
996 if (!registrationList.contains(rt.getIdentity()))
997 {
998 lockAndRegister(rt, lockMode, registeredObjects);
999 }
1000 }
1001 }
1002 }
1003 }
1004
1005 private void lockAndRegisterCollections(ClassDescriptor cld, Object sourceObject, int lockMode, List registeredObjects) throws LockNotGrantedException
1006 {
1007 if (implicitLocking)
1008 {
1009 Iterator i = cld.getCollectionDescriptors(true).iterator();
1010 while (i.hasNext())
1011 {
1012 CollectionDescriptor cds = (CollectionDescriptor) i.next();
1013 Object col = cds.getPersistentField().get(sourceObject);
1014 if (col != null)
1015 {
1016 CollectionProxy proxy = ProxyHelper.getCollectionProxy(col);
1017 if (proxy != null)
1018 {
1019 if (!proxy.isLoaded())
1020 {
1021 if (log.isDebugEnabled()) log.debug("adding self as listener to collection proxy");
1022 proxy.addListener(this);
1023 registeredCollectionProxies.add(proxy);
1024 continue;
1025 }
1026 }
1027 Iterator colIterator = BrokerHelper.getCollectionIterator(col);
1028 Object item = null;
1029 try
1030 {
1031 while (colIterator.hasNext())
1032 {
1033 item = colIterator.next();
1034 RuntimeObject rt = new RuntimeObject(item, this);
1035 if (rt.isProxy())
1036 {
1037 IndirectionHandler handler = ProxyHelper.getIndirectionHandler(item);
1038 if (!handler.alreadyMaterialized())
1039 {
1040 registerToIndirectionHandler(handler);
1041 continue;
1042 }
1043 else
1044 {
1045
1046
1047 item = handler.getRealSubject();
1048 }
1049 }
1050 if (!registrationList.contains(rt.getIdentity()))
1051 {
1052 lockAndRegister(rt, lockMode, registeredObjects);
1053 }
1054 }
1055 }
1056 catch (LockNotGrantedException e)
1057 {
1058 String eol = SystemUtils.LINE_SEPARATOR;
1059 log.error("Lock not granted, while lock collection references[" +
1060 eol + "current reference descriptor:" +
1061 eol + cds.toXML() +
1062 eol + "object to lock: " + item +
1063 eol + "main object class: " + sourceObject.getClass().getName() +
1064 eol + "]", e);
1065 throw e;
1066 }
1067 }
1068 }
1069 }
1070 }
1071
1072
1073
1074
1075
1076
1077
1078 public void beforeMaterialization(IndirectionHandler handler, Identity oid)
1079 {
1080
1081 }
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 public void afterMaterialization(IndirectionHandler handler, Object materializedObject)
1092 {
1093 try
1094 {
1095 Identity oid = handler.getIdentity();
1096 if (log.isDebugEnabled())
1097 log.debug("deferred registration: " + oid);
1098 if(!isOpen())
1099 {
1100 log.error("Proxy object materialization outside of a running tx, obj=" + oid);
1101 try{throw new Exception("Proxy object materialization outside of a running tx, obj=" + oid);}catch(Exception e)
1102 {
1103 e.printStackTrace();
1104 }
1105 }
1106 ClassDescriptor cld = getBroker().getClassDescriptor(materializedObject.getClass());
1107 RuntimeObject rt = new RuntimeObject(materializedObject, oid, cld, false, false);
1108 lockAndRegister(rt, Transaction.READ, isImplicitLocking(), getRegistrationList());
1109 }
1110 catch (Throwable t)
1111 {
1112 log.error("Register materialized object with this tx failed", t);
1113 throw new LockNotGrantedException(t.getMessage());
1114 }
1115 unregisterFromIndirectionHandler(handler);
1116 }
1117
1118 protected synchronized void unRegisterFromAllIndirectionHandlers()
1119 {
1120
1121
1122 for (int i = registeredIndirectionHandlers.size() - 1; i >= 0; i--)
1123 {
1124 unregisterFromIndirectionHandler((IndirectionHandler) registeredIndirectionHandlers.get(i));
1125 }
1126 }
1127
1128 protected synchronized void unRegisterFromAllCollectionProxies()
1129 {
1130 for (int i = registeredCollectionProxies.size() - 1; i >= 0; i--)
1131 {
1132 unregisterFromCollectionProxy((CollectionProxy) registeredCollectionProxies.get(i));
1133 }
1134 }
1135
1136 protected synchronized void unregisterFromCollectionProxy(CollectionProxy handler)
1137 {
1138 handler.removeListener(this);
1139 registeredCollectionProxies.remove(handler);
1140 }
1141
1142 protected synchronized void unregisterFromIndirectionHandler(IndirectionHandler handler)
1143 {
1144 handler.removeListener(this);
1145 registeredIndirectionHandlers.remove(handler);
1146 }
1147
1148 protected synchronized void registerToIndirectionHandler(IndirectionHandler handler)
1149 {
1150 handler.addListener(this);
1151 registeredIndirectionHandlers.add(handler);
1152 }
1153
1154
1155
1156
1157
1158 protected void registerUnmaterializedLocks(Object obj)
1159 {
1160 unmaterializedLocks.add(obj);
1161 }
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174 public PersistenceBrokerInternal getBrokerInternal()
1175 {
1176 if (broker == null || broker.isClosed())
1177 {
1178 checkOpen();
1179 try
1180 {
1181 checkForDB();
1182 broker = PersistenceBrokerFactoryFactory.instance().createPersistenceBroker(curDB.getPBKey());
1183 }
1184 catch (PBFactoryException e)
1185 {
1186 log.error("Cannot obtain PersistenceBroker from PersistenceBrokerFactory, " +
1187 "found PBKey was " + curDB.getPBKey(), e);
1188 throw new PersistenceBrokerException(e);
1189 }
1190 }
1191 return broker;
1192 }
1193
1194 public PersistenceBroker getBroker()
1195 {
1196 return getBrokerInternal();
1197 }
1198
1199
1200
1201
1202
1203 protected boolean hasBroker()
1204 {
1205 return broker != null && !broker.isClosed();
1206 }
1207
1208 protected void cleanupBroker()
1209 {
1210 if(hasBroker())
1211 {
1212 try
1213 {
1214 if(broker.isInTransaction())
1215 {
1216 broker.abortTransaction();
1217 }
1218 }
1219 finally
1220 {
1221 broker.close();
1222 broker = null;
1223 }
1224 }
1225 }
1226
1227
1228
1229
1230 public void configure(Configuration config) throws ConfigurationException
1231 {
1232 }
1233
1234
1235
1236
1237 public synchronized void setImplicitLocking(boolean value)
1238 {
1239 implicitLocking = value;
1240 }
1241
1242 public boolean isImplicitLocking()
1243 {
1244 return implicitLocking;
1245 }
1246
1247
1248
1249
1250 public void beforeLoading(CollectionProxyDefaultImpl colProxy)
1251 {
1252
1253 }
1254
1255
1256
1257
1258
1259 public void afterLoading(CollectionProxyDefaultImpl colProxy)
1260 {
1261 if (log.isDebugEnabled()) log.debug("loading a proxied collection a collection: " + colProxy);
1262 Collection data = colProxy.getData();
1263 for (Iterator iterator = data.iterator(); iterator.hasNext();)
1264 {
1265 Object o = iterator.next();
1266 if(!isOpen())
1267 {
1268 log.error("Collection proxy materialization outside of a running tx, obj=" + o);
1269 try{throw new Exception("Collection proxy materialization outside of a running tx, obj=" + o);}
1270 catch(Exception e)
1271 {e.printStackTrace();}
1272 }
1273 else
1274 {
1275 Identity oid = getBroker().serviceIdentity().buildIdentity(o);
1276 ClassDescriptor cld = getBroker().getClassDescriptor(ProxyHelper.getRealClass(o));
1277 RuntimeObject rt = new RuntimeObject(o, oid, cld, false, ProxyHelper.isProxy(o));
1278 lockAndRegister(rt, Transaction.READ, isImplicitLocking(), getRegistrationList());
1279 }
1280 }
1281 unregisterFromCollectionProxy(colProxy);
1282 }
1283
1284 protected void performTransactionAwareBeforeCommit()
1285 {
1286 Enumeration en = objectEnvelopeTable.elements();
1287 while (en.hasMoreElements())
1288 {
1289 ((ObjectEnvelope) en.nextElement()).beforeCommit();
1290 }
1291 }
1292 protected void performTransactionAwareAfterCommit()
1293 {
1294 Enumeration en = objectEnvelopeTable.elements();
1295 try
1296 {
1297 while (en.hasMoreElements())
1298 {
1299 ((ObjectEnvelope) en.nextElement()).afterCommit();
1300 }
1301 }
1302 catch(Exception e)
1303 {
1304 log.error("Unexpected error while perform 'TransactionAware#afterCommit()' listener after commit of objects," +
1305 " after commit you can't rollback - exception will be skipped.", e);
1306 }
1307 }
1308 protected void performTransactionAwareBeforeRollback()
1309 {
1310 Enumeration en = objectEnvelopeTable.elements();
1311 while (en.hasMoreElements())
1312 {
1313 try
1314 {
1315 ((ObjectEnvelope) en.nextElement()).beforeAbort();
1316 }
1317 catch(Exception e)
1318 {
1319 log.error("Unexpected error while perform 'TransactionAware#beforeAbort()' listener before rollback of objects" +
1320 " - exception will be skipped to complete rollback.", e);
1321 }
1322 }
1323 }
1324 protected void performTransactionAwareAfterRollback()
1325 {
1326 Enumeration en = objectEnvelopeTable.elements();
1327 try
1328 {
1329 while (en.hasMoreElements())
1330 {
1331 ((ObjectEnvelope) en.nextElement()).afterAbort();
1332 }
1333 }
1334 catch(Exception e)
1335 {
1336 log.error("Unexpected error while perform 'TransactionAware#afterAbort()' listener after rollback of objects" +
1337 " - exception will be skipped.", e);
1338 }
1339 }
1340
1341
1342
1343
1344 protected boolean isTransient(ClassDescriptor cld, Object obj, Identity oid)
1345 {
1346
1347 boolean isNew = oid != null && oid.isTransient();
1348
1349
1350
1351
1352
1353
1354
1355 if(!isNew)
1356 {
1357 final PersistenceBroker pb = getBroker();
1358 if(cld == null)
1359 {
1360 cld = pb.getClassDescriptor(obj.getClass());
1361 }
1362 isNew = pb.serviceBrokerHelper().hasNullPKField(cld, obj);
1363 if(!isNew)
1364 {
1365 if(oid == null)
1366 {
1367 oid = pb.serviceIdentity().buildIdentity(cld, obj);
1368 }
1369 final ObjectEnvelope mod = objectEnvelopeTable.getByIdentity(oid);
1370 if(mod != null)
1371 {
1372
1373 isNew = mod.needsInsert();
1374 }
1375 else
1376 {
1377
1378
1379 isNew = pb.serviceObjectCache().lookup(oid) == null
1380 && !pb.serviceBrokerHelper().doesExist(cld, oid, obj);
1381 }
1382 }
1383 }
1384 return isNew;
1385 }
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395 public void setCascadingDelete(Class target, String referenceField, boolean doCascade)
1396 {
1397 ClassDescriptor cld = getBroker().getClassDescriptor(target);
1398 ObjectReferenceDescriptor ord = cld.getObjectReferenceDescriptorByName(referenceField);
1399 if(ord == null)
1400 {
1401 ord = cld.getCollectionDescriptorByName(referenceField);
1402 }
1403 if(ord == null)
1404 {
1405 throw new CascadeSettingException("Invalid reference field name '" + referenceField
1406 + "', can't find 1:1, 1:n or m:n relation with that name in " + target);
1407 }
1408 runtimeCascadeDeleteMap.put(ord, (doCascade ? Boolean.TRUE : Boolean.FALSE));
1409 }
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420 public void setCascadingDelete(Class target, boolean doCascade)
1421 {
1422 ClassDescriptor cld = getBroker().getClassDescriptor(target);
1423 List extents = cld.getExtentClasses();
1424 Boolean result = doCascade ? Boolean.TRUE : Boolean.FALSE;
1425 setCascadingDelete(cld, result);
1426 if(extents != null && extents.size() > 0)
1427 {
1428 for(int i = 0; i < extents.size(); i++)
1429 {
1430 Class extent = (Class) extents.get(i);
1431 ClassDescriptor tmp = getBroker().getClassDescriptor(extent);
1432 setCascadingDelete(tmp, result);
1433 }
1434 }
1435 }
1436
1437 private void setCascadingDelete(ClassDescriptor cld, Boolean cascade)
1438 {
1439 List singleRefs = cld.getObjectReferenceDescriptors(true);
1440 for(int i = 0; i < singleRefs.size(); i++)
1441 {
1442 Object o = singleRefs.get(i);
1443 runtimeCascadeDeleteMap.put(o, cascade);
1444 }
1445 List collectionRefs = cld.getCollectionDescriptors(true);
1446 for(int i = 0; i < collectionRefs.size(); i++)
1447 {
1448 Object o = collectionRefs.get(i);
1449 runtimeCascadeDeleteMap.put(o, cascade);
1450 }
1451 }
1452
1453 private HashMap runtimeCascadeDeleteMap = new HashMap();
1454
1455
1456
1457
1458 protected boolean cascadeDeleteFor(ObjectReferenceDescriptor ord)
1459 {
1460 boolean result;
1461 Boolean runtimeSetting = (Boolean) runtimeCascadeDeleteMap.get(ord);
1462 if(runtimeSetting == null)
1463 {
1464
1465
1466
1467 result = ord.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT;
1468 }
1469 else
1470 {
1471 result = runtimeSetting.booleanValue();
1472 }
1473 return result;
1474 }
1475
1476 int getImpliciteLockType(int parentLockMode)
1477 {
1478 return (parentLockMode == Transaction.WRITE && impliciteWriteLocks) ? Transaction.WRITE : Transaction.READ;
1479 }
1480
1481
1482
1483
1484
1485 public boolean isOrdering()
1486 {
1487 return ordering;
1488 }
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500 public void setOrdering(boolean ordering)
1501 {
1502 this.ordering = ordering;
1503 }
1504
1505
1506
1507
1508
1509
1510
1511
1512 static class CascadeSettingException extends OJBRuntimeException
1513 {
1514 public CascadeSettingException()
1515 {
1516 }
1517
1518 public CascadeSettingException(String msg)
1519 {
1520 super(msg);
1521 }
1522
1523 public CascadeSettingException(Throwable cause)
1524 {
1525 super(cause);
1526 }
1527
1528 public CascadeSettingException(String msg, Throwable cause)
1529 {
1530 super(msg, cause);
1531 }
1532 }
1533 }