KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdo > VersantPersistenceManagerImp


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdo;
13
14 import com.versant.core.common.Debug;
15 import com.versant.core.common.*;
16 import com.versant.core.jdo.sco.VersantSCOCollection;
17 import com.versant.core.metadata.*;
18 import com.versant.core.jdo.query.mem.MemQueryCompiler;
19
20 import javax.jdo.*;
21 import javax.jdo.spi.JDOImplHelper;
22 import javax.jdo.spi.PersistenceCapable;
23 import javax.jdo.spi.StateManager;
24
25 import javax.transaction.Status JavaDoc;
26 import javax.transaction.Synchronization JavaDoc;
27 import javax.transaction.xa.XAException JavaDoc;
28 import javax.transaction.xa.XAResource JavaDoc;
29 import javax.transaction.xa.Xid JavaDoc;
30
31 import java.lang.reflect.Modifier JavaDoc;
32 import java.lang.ref.Reference JavaDoc;
33 import java.sql.Connection JavaDoc;
34 import java.util.*;
35
36 import com.versant.core.common.BindingSupportImpl;
37 //import com.versant.core.vds.util.Loid;
38
import com.versant.core.storagemanager.StorageManager;
39 import com.versant.core.storagemanager.ApplicationContext;
40
41 /**
42  * This is a global StateManager instance for a PersistenceManagerImp. It will
43  * assign a state managing object to a managed PersistenceCapable instance.
44  */

45 public final class VersantPersistenceManagerImp
46         implements VersantPersistenceManager, ApplicationContext, Transaction, PersistenceContext
47         , XAResource JavaDoc, Synchronization JavaDoc {
48
49     /**
50      * Double linked list of dirty instances.
51      *
52      * @see PCStateMan#next
53      * @see PCStateMan#prev
54      */

55     private PCStateMan txDirtyListHead;
56     private PCStateMan txDirtyListTail;
57
58     public VersantPersistenceManagerImp prev;
59     public VersantPersistenceManagerImp next;
60     public boolean idle;
61
62     /**
63      * The list of instances that has been marked for delete in the current tx.
64      */

65     private final DeletePacket toBeDeleted;
66     /**
67      * This is used to transport the dirty stuff to the server.
68      */

69     public final StatesToStore storeOidStateContainer;
70     /**
71      * while busy with a retrieve graph this will be set to true
72      */

73     private boolean retrieveing;
74     /**
75      * This is the instances that has been retrieved already.
76      */

77     private final Set retrieveSet = new HashSet();
78
79     /**
80      * The user object set by a client.
81      */

82     private Object JavaDoc userObject;
83
84     /**
85      * A Transaction may be associated with an Synchronization instance. If so this will be set to
86      * the supplied intstance
87      *
88      * @see #setSynchronization
89      */

90
91     private Synchronization JavaDoc synchronizationInstance;
92
93
94     /**
95      * This is a cheat to quickly get the sm for a pc instance.
96      * When getPM is called on the stateManager it sets itself to the
97      */

98     public PCStateMan requestedPCState;
99     public final ModelMetaData modelMetaData;
100     private LocalPMCache cache;
101     public final JDOImplHelper jdoImplHelper = JDOImplHelper.getInstance();
102
103     /**
104      * Indication if tx is active.
105      */

106     private boolean transactionActive;
107     private boolean busyWithRollback;
108
109     /**
110      * The counter that is used in creating NewObjectOID.
111      */

112     private int counter = 0;
113
114     private boolean retainValues;
115     private boolean restoreValues;
116     private boolean optimistic;
117     private boolean nontransactionalRead;
118     private boolean nontransactionalWrite;
119     private boolean ignoreCache;
120     private boolean multithreaded;
121
122     /**
123      * If PersistenceManager is closed.
124      */

125     private boolean closed;
126
127     /**
128      * The factory that created this pm.
129      */

130     private final VersantPMFInternal pmf;
131
132     private final MemQueryCompiler memQueryCompiler;
133
134     /**
135      * This will force the instance to be thrown away by the pool.
136      */

137     private boolean mustNotPool;
138     private boolean inPool;
139
140     /**
141      * This is the proxy that is used for all client access.
142      * This is used to decouple us from any instances left lying around.
143      * This proxy ref must be reset to a new instance every time that it
144      * is taken from the pool to be given out to a client.
145      */

146     private PMProxy proxy;
147
148     /**
149      * This is a bitset of all dirty classes.
150      */

151     private final CmdBitSet dirtyCmdBits;
152     private final StorageManager sm;
153
154     /**
155      * This variable is used to control the strict adherence to the spec. when
156      * transaction commits. If false then instances read in the tx but which is
157      * p-nontx will be hollowed.
158      */

159     private boolean strict;
160     private boolean interceptDfgFieldAccess = true;
161
162     private boolean checkModelConsistencyOnCommit;
163
164     public static final String JavaDoc LANGUAGE_SQL = "SQL";
165     public static final String JavaDoc LANGUAGE_EJBQL = "EJBQL";
166
167
168     // These fields keep track of OIDs/instances of objectid-class'es and
169
// classes to evict from l2 cache if the transaction commits (epc = Evict
170
// Post Commit).
171
private Object JavaDoc[] epcObjects;
172     private int epcObjectCount;
173     private int[] epcClasses;
174     private int epcClassCount;
175     private boolean[] epcClassPresent;
176     private boolean epcAll;
177
178     private LifecycleListenerManager listeners;
179
180     private Reference JavaDoc activeReference;
181
182     public VersantPersistenceManagerImp(VersantPMFInternal pmf,
183             ModelMetaData modelMetaData, StorageManager sm,
184             LocalPMCache jdoManagedCache,
185             MemQueryCompiler memQueryCompiler) {
186         this.pmf = pmf;
187         this.modelMetaData = modelMetaData;
188         this.sm = sm;
189         this.storeOidStateContainer = new StatesToStore(modelMetaData);
190         this.toBeDeleted = new DeletePacket(modelMetaData);
191         dirtyCmdBits = new CmdBitSet(modelMetaData);
192         this.cache = jdoManagedCache;
193         this.cache.setPm(this);
194         this.memQueryCompiler = memQueryCompiler;
195     }
196
197     private void createProxy() {
198         if (multithreaded) {
199             proxy = new SynchronizedPMProxy(this);
200         } else {
201             proxy = new UnsynchronizedPMProxy(this);
202         }
203     }
204
205     public boolean isInterceptDfgFieldAccess() {
206         return interceptDfgFieldAccess;
207     }
208
209     public void setInterceptDfgFieldAccess(boolean on) {
210         if (interceptDfgFieldAccess == on) return;
211         cache.setInterceptDfgFieldAccess(
212                 interceptDfgFieldAccess = on);
213     }
214
215     public boolean isStrict() {
216         return strict;
217     }
218
219     public void setStrict(boolean strict) {
220         this.strict = strict;
221     }
222
223     public PMProxy getProxy() {
224         return proxy;
225     }
226
227     public boolean isInPool() {
228         return inPool;
229     }
230
231     public void setMustNotPool(boolean mustNotPool) {
232         this.mustNotPool = mustNotPool;
233     }
234
235     public boolean isMustNotPool() {
236         return mustNotPool;
237     }
238
239     /**
240      * This is called by the pool instance the moment comes in or out of the
241      * pool.
242      */

243     public void setInPool(boolean inPool) {
244         this.inPool = inPool;
245         if (inPool) {
246             proxy = null;
247         } else {
248             createProxy();
249             if (managed) managedClosed = false;
250         }
251     }
252
253     /**
254      * Reset the proxy so that if a client has a weak/soft ref to pm he will
255      * get a closed exception. Then return us to our PMF.
256      */

257     protected void finalize() throws Throwable JavaDoc {
258         boolean txWasActive = transactionActive;
259         if (transactionActive) {
260             rollback();
261         }
262         proxy.resetPM();
263         pmf.pmClosedNotification(this, true, txWasActive);
264     }
265
266     /**
267      * Sets the master on the detail in a Master/Detail relationship. If
268      * removeFromCurrentMaster is true then the detail is removed from its
269      * current master (if any and if different).
270      */

271     public void setMasterOnDetail(PersistenceCapable detail, int managedFieldNo,
272             PersistenceCapable master, boolean removeFromCurrentMaster) {
273         getInternalSM(detail).setMaster(managedFieldNo, master,
274                 removeFromCurrentMaster);
275     }
276
277     /**
278      * Get a collection field from a pc. This is used to implement many-to-many
279      * relationships.
280      */

281     public VersantSCOCollection getCollectionField(PersistenceCapable pc,
282             int fieldNo) {
283         PCStateMan sm = getInternalSM(pc);
284         return (VersantSCOCollection)sm.getObjectField(null, fieldNo, null);
285     }
286
287     public Object JavaDoc getObjectField(PersistenceCapable pc,
288             int fieldNo) {
289         PCStateMan sm = getInternalSM(pc);
290         return sm.getObjectField(null, fieldNo, null);
291     }
292
293     public String JavaDoc getConnectionURL(String JavaDoc dataStore) {
294         try {
295             return pmf.getConnectionURL();
296         } catch (Exception JavaDoc e) {
297             handleException(e);
298             return null;
299         }
300     }
301
302     public void cancelQueryExecution() {
303         // todo implement jdoConnection.cancelQueryExecution();
304
}
305
306     public String JavaDoc getConnectionDriverName(String JavaDoc dataStore) {
307         try {
308             return pmf.getConnectionDriverName();
309         } catch (Exception JavaDoc e) {
310             handleException(e);
311             return null;
312         }
313     }
314
315     public Connection JavaDoc getJdbcConnection(String JavaDoc datastore) {
316         if (!transactionActive) {
317             throw BindingSupportImpl.getInstance().invalidOperation(
318                     "A JDBC Connection may only be obtained within a active JDO transaction.");
319         }
320         try {
321             return (Connection JavaDoc)sm.getDatastoreConnection();
322         } catch (Exception JavaDoc e) {
323             handleException(e);
324             return null;
325         }
326     }
327
328     /**
329      *
330      */

331     public void flushIfDepOn(int[] cmdBits) {
332         if (cmdBits != null && dirtyCmdBits.containsAny(cmdBits)) flushRetainState();
333     }
334
335     public void loadFetchGroup(Object JavaDoc pc, String JavaDoc name) {
336         try {
337             if (!(pc instanceof PersistenceCapable)) {
338                 String JavaDoc msg;
339                 if (pc == null) {
340                     msg = "Instance is null";
341                 } else {
342                     msg = "Instance is not a persistence class: " +
343                             pc.getClass().getName();
344                 }
345                 throw BindingSupportImpl.getInstance().runtime(msg);
346             }
347             PCStateMan sm = getInternalSM((PersistenceCapable)pc);
348             if (sm == null) {
349                 throw BindingSupportImpl.getInstance().invalidOperation("Instance is not managed by JDO (it is transient): " +
350                         Utils.toString(pc));
351             }
352             sm.loadFetchGroup(name);
353         } catch (RuntimeException JavaDoc e) {
354             handleException(e);
355         }
356     }
357
358     public boolean isRetainValues() {
359         return retainValues;
360     }
361
362     public boolean isRestoreValues() {
363         return restoreValues;
364     }
365
366     public boolean isOptimistic() {
367         return optimistic;
368     }
369
370     public boolean isNontransactionalRead() {
371         return nontransactionalRead;
372     }
373
374     public boolean isNontransactionalWrite() {
375         return nontransactionalWrite;
376     }
377
378     public boolean isIgnoreCache() {
379         return ignoreCache;
380     }
381
382     public void evict(Object JavaDoc pc) {
383         try {
384             if (pc == null) return;
385             PersistenceCapable persistenceCapable = checkPersCapable(pc);
386             PersistenceManager pm = persistenceCapable.jdoGetPersistenceManager();
387             // This instance is not managed. So return.
388
if (pm == null) return;
389             checkPM(pm, proxy);
390             getInternalSM(persistenceCapable).evict();
391         } catch (Exception JavaDoc e) {
392             handleException(e);
393         }
394     }
395
396     public void evictAll() {
397         try {
398             cache.evict();
399         } catch (Exception JavaDoc e) {
400             handleException(e);
401         }
402     }
403
404     public void evictAll(Object JavaDoc[] pcs) {
405         for (int i = pcs.length - 1; i >= 0; i--) {
406             evict(pcs[i]);
407         }
408     }
409
410     public void evictAll(Collection pcs) {
411         try {
412             Object JavaDoc[] persistenceCapables = new Object JavaDoc[pcs.size()];
413             pcs.toArray(persistenceCapables);
414             for (int i = persistenceCapables.length - 1; i >= 0; i--) {
415                 evict(persistenceCapables[i]);
416             }
417         } catch (Exception JavaDoc e) {
418             handleException(e);
419         }
420     }
421
422     public Object JavaDoc getObjectId(Object JavaDoc pc) {
423         try {
424             if (pc == null) {
425                 throw BindingSupportImpl.getInstance().invalidOperation(
426                         "The supplied Object param is null");
427             }
428
429             if (!(pc instanceof PersistenceCapable))
430             // pmPreCheck throws exception in this case
431
{
432                 return null;
433             }
434
435             PCStateMan pcStateObject = pmPreCheck(pc);
436             if (pcStateObject != null) {
437                 return pcStateObject.getObjectId(null);
438             } else {
439                 return null;
440             }
441         } catch (RuntimeException JavaDoc e) {
442             handleException(e);
443             return null;
444         }
445     }
446
447     public Object JavaDoc getExternalOID(OID oid) {
448         PCStateMan sm = cache.getByOID(oid, false);
449         if (sm != null) {
450             return sm.getObjectId(null);
451         } else {
452             ClassMetaData classMetaData = oid.getAvailableClassMetaData();
453             if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_DATASTORE) {
454                 return new VersantOid(oid, modelMetaData, oid.isResolved());
455             } else if (classMetaData.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
456                 Object JavaDoc pcID = jdoImplHelper.newObjectIdInstance(
457                         classMetaData.cls);
458                 oid.populateObjectIdClassInstance(pcID);
459                 return pcID;
460             } else {
461                 throw BindingSupportImpl.getInstance().unsupported();
462             }
463         }
464     }
465
466     public Object JavaDoc getObjectByIDString(String JavaDoc value, boolean toValidate) {
467         return getObjectByIDString(value, toValidate, true);
468     }
469
470     public Object JavaDoc getObjectByIDString(String JavaDoc value, boolean toValidate,
471             boolean resolved) {
472         try {
473             OID oid = modelMetaData.newOIDFromIDString(value, resolved);
474             return getObjectById(oid, toValidate);
475         } catch (Exception JavaDoc e) {
476             handleException(e);
477             return null;
478         }
479     }
480
481     public Object JavaDoc getTransactionalObjectId(Object JavaDoc pc) {
482         try {
483             return getObjectId(pc);
484         } catch (Exception JavaDoc e) {
485             handleException(e);
486             return null;
487         }
488     }
489
490
491 // public void batchDelete(Query q, Object[] params) {
492
// VesantQueryImp clientQuery = (VesantQueryImp) q;
493
// clientQuery.getQParamsForBatchProc(params);
494
// throw new NotImplementedException();
495
// }
496

497     public boolean isClosed() {
498         checkInPool();
499         if (!managed) {
500             return closed;
501         } else {
502             return managedClosed;
503         }
504     }
505
506     /**
507      * This is called by the user to close the pm. If in a managed environment the managedClosed
508      * flag will be set.
509      * <p/>
510      * If pooling is enabled the the instance must be reset to
511      * be put back in the pool.
512      * <p/>
513      * If pooling is not enabled then the instance must be reset to avoid mem leaks.
514      * The instance will never be used again.
515      * <p/>
516      * The current transaction will be rolled back if active.
517      * This means that synchronization events will be fired.
518      */

519     public synchronized void close() {
520         checkClosed();
521         if (!managed) {
522             checkCloseWithActiveTx();
523             boolean txWasActive = transactionActive;
524             if (transactionActive) {
525                 rollback();
526             }
527             proxy.resetPM();
528             pmf.pmClosedNotification(this, false, txWasActive);
529         } else {
530             managedClosed = true;
531         }
532     }
533
534     private void checkCloseWithActiveTx() {
535         if (transactionActive && !pmf.isAllowPmCloseWithTxOpen()) {
536             throw BindingSupportImpl.getInstance().invalidOperation(
537             
538                     "May not close 'PersistenceManager' with active transaction");
539  
540                     
541         }
542     }
543
544     /**
545      * Destroy the PM. It cannot be reused after this call.
546      */

547     public void destroy() {
548         try {
549             sm.reset();
550             resetEpcFields();
551             reset();
552             cache.clear();
553             this.closed = true;
554         } catch (Exception JavaDoc e) {
555             handleException(e);
556         }
557     }
558
559     public boolean isActualClosed() {
560         return closed;
561     }
562
563     public Transaction currentTransaction() {
564         return this;
565     }
566
567     public void refresh(Object JavaDoc pc) {
568         try {
569             /**
570              * if pc is transient / non-managed then return.
571              */

572             if (isTransient(pc)) return;
573             pmPreCheck(pc).refresh();
574         } catch (Exception JavaDoc e) {
575             handleException(e);
576         }
577     }
578
579     public void setPmCacheRefType(Object JavaDoc pc, int type) {
580         pmPreCheck(pc).cacheEntry.changeToRefType(cache.queue, type);
581     }
582
583     public void setPmCacheRefType(Object JavaDoc[] pcs, int type) {
584         for (int i = 0; i < pcs.length; i++) {
585             if (pcs[i] != null) setPmCacheRefType(pcs[i], type);
586         }
587     }
588
589     public void setPmCacheRefType(Collection col, int type) {
590         for (Iterator iterator = col.iterator(); iterator.hasNext();) {
591             Object JavaDoc o = iterator.next();
592             if (o != null) setPmCacheRefType(o, type);
593         }
594     }
595
596     public void setPmCacheRefType(int type) {
597         cache.setCurrentRefType(type);
598     }
599
600     public int getPmCacheRefType() {
601         return cache.getCurrentRefType();
602     }
603
604     public void refreshAll(Object JavaDoc[] pcs) {
605         try {
606             for (int i = 0; i < pcs.length; i++) {
607                 refresh(pcs[i]);
608             }
609         } catch (Exception JavaDoc e) {
610             handleException(e);
611         }
612     }
613
614     public void refreshAll(Collection pcs) {
615         if (pcs instanceof QueryResult) {
616             cache.setOverWriteMode(true);
617             try {
618                 Iterator iter = ((QueryResult)pcs).createInternalIterNoFlush();
619                 while (iter.hasNext()) iter.next();
620             } catch (Exception JavaDoc e) {
621                 handleException(e);
622             } finally {
623                 cache.setOverWriteMode(false);
624             }
625         } else {
626             try {
627                 for (Iterator iterator = pcs.iterator(); iterator.hasNext();) {
628                     refresh(iterator.next());
629                 }
630             } catch (Exception JavaDoc e) {
631                 handleException(e);
632             }
633         }
634     }
635
636     public void refreshAll() {
637         try {
638             if (transactionActive) {
639                 cache.doRefresh(strict);
640             }
641         } catch (Exception JavaDoc e) {
642             handleException(e);
643         }
644     }
645
646     public Query newQuery() {
647         try {
648             return new VersantQueryImp(proxy);
649         } catch (Exception JavaDoc e) {
650             handleException(e);
651             return null;
652         }
653     }
654
655     public Query newQuery(Object JavaDoc compiled) {
656 // if (compiled instanceof JavaQuery) {
657
// return newQuery((JavaQuery) compiled);
658
// }
659
try {
660             VersantQueryImp other = null;
661             try {
662                 other = (VersantQueryImp)compiled;
663             } catch (Exception JavaDoc e) {
664                 throw BindingSupportImpl.getInstance().invalidOperation(
665                         "The supplied instance is not supported to re-create a query from.");
666             }
667             return new VersantQueryImp(proxy, other);
668         } catch (RuntimeException JavaDoc e) {
669             handleException(e);
670             return null;
671         }
672     }
673
674 // public Query newQuery(JavaQuery javaQuery) {
675
// try {
676
// JavaQueryParams query = null;
677
// try {
678
// query = (JavaQueryParams) javaQuery;
679
// } catch (ClassCastException e) {
680
// throw BindingSupportImpl.getInstance().invalidOperation(
681
// "JavaQuery has not been enhanced.");
682
// }
683
// VesantQueryImp clientQuery = new VesantQueryImp(proxy);
684
// clientQuery.setClass(query.getQueryClass());
685
// clientQuery.setFilter(query.getFilter());
686
// clientQuery.setOrdering(query.getOrdering());
687
// clientQuery.declareParameters(query.getParameters());
688
// clientQuery.declareVariables(query.getVariables());
689
// return clientQuery;
690
// } catch (Exception e) {
691
// handleException(e);
692
// return null;
693
// }
694
// }
695
//
696
// public Query newNamedQuery(Class cls, String queryName) {
697
// return null;
698
// }
699

700     public Query newQuery(String JavaDoc language, Object JavaDoc query) {
701         try {
702             if (language != null) {
703                 language = language.toUpperCase();
704             }
705             if (LANGUAGE_SQL.equals(language)) {
706                 VersantQueryImp clientQuery = new VersantQueryImp(proxy,
707                         QueryDetails.LANGUAGE_SQL);
708                 clientQuery.setFilter((String JavaDoc)query);
709                 return clientQuery;
710
711             } else if (LANGUAGE_EJBQL.equals(language)) {
712                 VersantQueryImp clientQuery = new VersantQueryImp(proxy,
713                         QueryDetails.LANGUAGE_EJBQL);
714                 clientQuery.setFilter((String JavaDoc)query);
715                 return clientQuery;
716             } else {
717                 return newQuery(query);
718             }
719         } catch (Exception JavaDoc e) {
720             handleException(e);
721             return null;
722         }
723     }
724
725     public Query newQuery(Class JavaDoc cls) {
726         try {
727             VersantQueryImp clientQuery = new VersantQueryImp(proxy);
728             clientQuery.setClass(cls);
729             return clientQuery;
730         } catch (Exception JavaDoc e) {
731             handleException(e);
732             return null;
733         }
734     }
735
736     public Query newQuery(Extent extent) {
737         try {
738             VersantQueryImp clientQuery = new VersantQueryImp(proxy);
739             clientQuery.setCandidates(extent);
740             return clientQuery;
741         } catch (Exception JavaDoc e) {
742             handleException(e);
743             return null;
744         }
745     }
746
747     public Query newQuery(Extent extent, String JavaDoc filter) {
748         try {
749             VersantQueryImp clientQuery = new VersantQueryImp(proxy);
750             clientQuery.setCandidates(extent);
751             clientQuery.setFilter(filter);
752             return clientQuery;
753         } catch (Exception JavaDoc e) {
754             handleException(e);
755             return null;
756         }
757     }
758
759     public Query newQuery(Class JavaDoc cls, Collection cln) {
760         try {
761             VersantQueryImp clientQuery = new VersantQueryImp(proxy);
762             clientQuery.setClass(cls);
763             clientQuery.setCandidates(cln);
764             return clientQuery;
765         } catch (Exception JavaDoc e) {
766             handleException(e);
767             return null;
768         }
769     }
770
771     public Query newQuery(Class JavaDoc cls, String JavaDoc filter) {
772         try {
773             VersantQueryImp clientQuery = new VersantQueryImp(proxy);
774             clientQuery.setClass(cls);
775             clientQuery.setFilter(filter);
776             return clientQuery;
777         } catch (Exception JavaDoc e) {
778             handleException(e);
779             return null;
780         }
781     }
782
783     public Query newQuery(Class JavaDoc cls, Collection cln, String JavaDoc filter) {
784         try {
785             VersantQueryImp clientQuery = new VersantQueryImp(proxy);
786             clientQuery.setClass(cls);
787             clientQuery.setCandidates(cln);
788             clientQuery.setFilter(filter);
789             return clientQuery;
790         } catch (Exception JavaDoc e) {
791             handleException(e);
792             return null;
793         }
794     }
795
796     public Class JavaDoc getObjectIdClass(Class JavaDoc cls) {
797         try {
798             if (cls == null) {
799                 return null;
800 // throw new JDOUserException("The supplied Class param is null");
801
}
802             if (!PersistenceCapable.class.isAssignableFrom(cls)) {
803                 return null;
804             }
805             if (Modifier.isAbstract(cls.getModifiers())) {
806                 return null;
807             }
808             ClassMetaData cmd = modelMetaData.getClassMetaData(cls);
809             if (cmd == null) {
810                 throw BindingSupportImpl.getInstance().invalidOperation(
811                         "The class is not specified as " + PersistenceCapable.class.getName() + " for the application");
812             }
813             if (cmd.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
814                 return cmd.objectIdClass;
815             } else {
816                 return VersantOid.class;
817             }
818         } catch (RuntimeException JavaDoc e) {
819             handleException(e);
820             return null;
821         }
822     }
823
824     public Object JavaDoc newObjectIdInstance(Class JavaDoc cls, String JavaDoc s) {
825         return newObjectIdInstance(cls, s, true);
826     }
827
828     public Object JavaDoc newObjectIdInstance(Class JavaDoc cls, String JavaDoc s, boolean resolved) {
829         try {
830             if (s == null || s.length() == 0) {
831                 throw BindingSupportImpl.getInstance().invalidOperation(
832                         "Please supply an non-null, non-empty String");
833             }
834             if (cls == null) { // assume datastore identity
835
return new VersantOid(
836                         modelMetaData.newOIDFromIDString(s, resolved),
837                         modelMetaData, resolved);
838             }
839             ClassMetaData cmd = modelMetaData.getClassMetaData(cls);
840             if (cmd == null) {
841                 throw BindingSupportImpl.getInstance().invalidOperation("There is no metadata registered for class '" +
842                         cls.getName() + "'");
843             }
844             if (cmd.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
845                 return jdoImplHelper.newObjectIdInstance(cls, s);
846             } else if (cmd.identityType == MDStatics.IDENTITY_TYPE_DATASTORE) {
847                 return new VersantOid(
848                         modelMetaData.newOIDFromIDString(s, resolved),
849                         modelMetaData, resolved);
850             } else {
851                 throw BindingSupportImpl.getInstance().invalidOperation("Class '" + cls.getName() +
852                         " uses non-durable identity");
853             }
854         } catch (RuntimeException JavaDoc e) {
855             handleException(e);
856             return null;
857         }
858     }
859
860     public void retrieve(Object JavaDoc o) {
861         try {
862             PCStateMan pcStateObject = pmPreCheck(o);
863             if (pcStateObject != null) {
864                 try {
865                     if (Debug.DEBUG) {
866                         if (retrieveing) {
867                             throw BindingSupportImpl.getInstance().internal(
868                                     "Retrieveing is already set");
869                         }
870                     }
871                     retrieveing = true;
872                     if (Debug.DEBUG) {
873                         if (retrieveSet.contains(pcStateObject.pc)) {
874                             throw BindingSupportImpl.getInstance().internal(
875                                     "RetrieveSet already contains pc");
876                         }
877                     }
878                     retrieveSet.add(pcStateObject.pc);
879                     pcStateObject.retrieve(this);
880                 } finally {
881                     retrieveing = false;
882                     retrieveSet.clear();
883                 }
884             }
885         } catch (RuntimeException JavaDoc e) {
886             if (BindingSupportImpl.getInstance().isOwnInternalException(e)) {
887                 handleException(e);
888             } else {
889                 throw e;
890             }
891         }
892     }
893
894     public void retrieveImp(Object JavaDoc o) {
895         if (o == null) return;
896         PCStateMan pcStateObject = pmPreCheck(o);
897         if (pcStateObject != null &&
898                 !retrieveSet.contains(pcStateObject.pc)) {
899             retrieveSet.add(pcStateObject.pc);
900             pcStateObject.retrieve(this);
901         }
902     }
903
904     public void retrieveAllImp(Object JavaDoc[] toRetrieve) {
905         for (int i = 0; i < toRetrieve.length; i++) {
906             retrieveImp(toRetrieve[i]);
907         }
908     }
909
910     public void retrieveAllImp(Collection toRetrieve) {
911         retrieveAllImp(toRetrieve.toArray());
912     }
913
914     public void retrieveAll(Collection collection) {
915         try {
916             retrieveAll(collection.toArray());
917         } catch (Exception JavaDoc e) {
918             handleException(e);
919         }
920     }
921
922     public void retrieveAll(Collection collection, boolean b) {
923         retrieveAll(collection);
924     }
925
926     public void retrieveAll(Object JavaDoc[] objects, boolean b) {
927         retrieveAll(objects);
928     }
929
930     public void retrieveAll(Object JavaDoc[] objects) {
931         try {
932             try {
933                 if (Debug.DEBUG) {
934                     if (retrieveing) {
935                         throw BindingSupportImpl.getInstance().internal(
936                                 "Retrieveing is already set");
937                     }
938                 }
939                 retrieveing = true;
940                 for (int i = 0; i < objects.length; i++) {
941                     retrieveImp(objects[i]);
942                 }
943             } finally {
944                 retrieveing = false;
945                 retrieveSet.clear();
946             }
947         } catch (RuntimeException JavaDoc e) {
948             if (BindingSupportImpl.getInstance().isOwnInternalException(e)) {
949                 handleException(e);
950             } else {
951                 throw e;
952             }
953         }
954     }
955
956     /**
957      * todo keep extent's around instead of creating a new one.
958      *
959      * @param persistenceCapableClass
960      * @param subclasses
961      * @return
962      */

963     public Extent getExtent(Class JavaDoc persistenceCapableClass, boolean subclasses) {
964         try {
965             return new ExtentImp(persistenceCapableClass, subclasses, proxy);
966         } catch (Exception JavaDoc e) {
967             handleException(e);
968             return null;
969         }
970     }
971
972     /**
973      * Util method to return the fetchgroup index.
974      */

975     private int getFgIndex(OID nOID, String JavaDoc fetchGroupName) {
976         int fgIndex = 0;
977         FetchGroup fg = nOID.getAvailableClassMetaData().getFetchGroup(
978                 fetchGroupName);
979         if (fg != null) {
980             fgIndex = fg.index;
981         }
982         return fgIndex;
983     }
984
985     public Object JavaDoc getObjectById(Object JavaDoc oid, boolean validate) {
986         if (oid == null) {
987             throw BindingSupportImpl.getInstance().invalidOperation(
988                     "The supplied oid is null");
989         }
990
991         PersistenceCapable pc = null;
992         try {
993             OID nOID = extractOID(oid);
994             PCStateMan stateMan = cache.getByOID(nOID, true);
995             if (stateMan == null) {
996                 if (!nOID.isNew()) {
997                     /**
998                      * A call to getObjectById(id, false) with a where
999                      * (idType == appId) and (oid.cmd.usekeygen == true)
1000                     * will always be validated against the db. This is done
1001                     * because an inconsistent mapping
1002                     * may arise.
1003                     *
1004                     * Scenario: A new instance of this type is created and made
1005                     * persistent. This instance is now in the
1006                     * managed cache with a internal tmp oid.
1007                     * A call to getObjectById(id, false) is made with a id
1008                     * value of 2 for example. This instance will also
1009                     * end up in the managed cache with a real app id with value 2.
1010                     * On a call to commit the keygen will allocate a value to
1011                     * the new id instance. If this value is also
1012                     * assigned the value '2' then there will both instances
1013                     * wants the same id but the are already assigned
1014                     * different pc instance values.
1015                     *
1016                     * Also added check for an unresolved oid that is in a hierarchy.
1017                     * Such oids are also always resolved.
1018                     * This could be changed later to keep such an instance in an
1019                     * initialised state.
1020                     */

1021                    if (validate
1022                            || (nOID.getAvailableClassMetaData().useKeyGen && nOID.getAvailableClassMetaData(
1023                            ).identityType == MDStatics.IDENTITY_TYPE_APPLICATION)
1024                            || (!nOID.isResolved() && nOID.getAvailableClassMetaData(
1025                            ).isInHeirachy())) {
1026                        checkNonTxRead();
1027                        OID nOIDcopy = nOID.copy();
1028                        stateMan = getStateMan(nOIDcopy, 0, -1, -1, validate);
1029
1030                        if (stateMan == null) {
1031                            throw BindingSupportImpl.getInstance().objectNotFound(
1032                                    "No row for " +
1033                                    nOID.getAvailableClassMetaData().storeClass + " " + nOID.toSString());
1034                        }
1035
1036                        pc = stateMan.pc;
1037                        stateMan.loadDFGIntoPC(this);
1038                    } else {
1039                        //create the sm
1040
PCStateMan sm = getStateObject();
1041                        sm.init(nOID, this);
1042                        pc = sm.pc;
1043                        cache.add(sm);
1044                    }
1045                } else {
1046                    throw BindingSupportImpl.getInstance().objectNotFound(
1047                            "No row for " + nOID.toSString());
1048                }
1049            } else {
1050                pc = stateMan.pc;
1051                if (validate && !stateMan.isTransactional(null)) {
1052                    checkNonTxRead();
1053                    if (stateMan.isHollow()) {
1054                        stateMan.loadDfgFromHollow();
1055                    } else {
1056                        getState(stateMan.oid, null, 0, -1, -1, true);
1057                    }
1058                }
1059            }
1060            return pc;
1061        } catch (Exception JavaDoc e) {
1062            handleException(e);
1063            return null;
1064        }
1065    }
1066
1067    public OID extractOID(Object JavaDoc oid) {
1068        OID nOID;
1069        if (oid instanceof VersantOid) {
1070            nOID = modelMetaData.convertJDOGenieOIDtoOID((VersantOid)oid);
1071            nOID = convertNewToActual(nOID);
1072        } else if (oid instanceof OID) {
1073            nOID = convertNewToActual((OID)oid);
1074        } else {
1075            nOID = modelMetaData.convertFromAppIdToOID(oid);
1076        }
1077        return nOID;
1078    }
1079
1080    /**
1081     * This is use by State implementations when they need to retrieve an
1082     * instance. This will typically be a result of graph navigation.
1083     * The oid parameter is not used when an embedded reference field is
1084     * being retrieved.
1085     */

1086    public Object JavaDoc getObjectByIdForState(OID oid, int stateFieldNo,
1087            int navClassIndex, OID fromOID) {
1088        try {
1089            PersistenceCapable pc;
1090            FieldMetaData fmd = fromOID.getAvailableClassMetaData().stateFields[stateFieldNo];
1091            if (fmd.embedded) {
1092                //create a managed instance of the embedded reference
1093
PCStateMan owningSM = cache.getByOID(fromOID, false);
1094                if (fmd.nullIndicatorFmd != null) {
1095                    if (owningSM.state.isFieldNullorZero(fmd.nullIndicatorFmd.stateFieldNo)) {
1096                        return null;
1097                    }
1098                }
1099                EmbeddedStateManager embeddedSm = owningSM.createEmbeddedSM(fmd);
1100                pc = embeddedSm.pc;
1101            } else {
1102                PCStateMan stateMan = cache.getByOID(oid, true);
1103                if (stateMan == null) {
1104                    stateMan = getStateMan(oid, 0, stateFieldNo, navClassIndex,
1105                            false);
1106                    if (stateMan != null) {
1107                        pc = stateMan.pc;
1108                        stateMan.loadDFGIntoPC(this);
1109                    } else {
1110                        pc = null;
1111                    }
1112                } else {
1113                    pc = stateMan.pc;
1114                    if (!stateMan.isTransactional(null)) {
1115                        checkNonTxRead();
1116                        //TODO why loadDfg. Is it not better to leave the state hollow
1117
if (stateMan.isHollow()) stateMan.loadDfgFromHollow();
1118                    }
1119                }
1120            }
1121            return pc;
1122        } catch (Exception JavaDoc e) {
1123            handleException(e);
1124            return null;
1125        }
1126    }
1127
1128    public final void checkNonTxRead() {
1129        if (!(transactionActive || nontransactionalRead)) {
1130            throw BindingSupportImpl.getInstance().invalidOperation(
1131                    "Must set nonTransactionalRead to true");
1132        }
1133    }
1134
1135    public final void checkNonTxWrite() {
1136        if (!(transactionActive || nontransactionalWrite)) {
1137            throw BindingSupportImpl.getInstance().invalidOperation(
1138                    "Must set nonTransactionalWrite to true");
1139        }
1140    }
1141
1142    public boolean doBeforeState(boolean isTransient, boolean isTransactional) {
1143        return ((restoreValues || isTransient || isTransactional) && transactionActive);
1144    }
1145
1146    private OID convertNewToActual(OID oid) {
1147        if (!oid.isNew()) {
1148            oid.getAvailableClassMetaData();
1149            return oid;
1150        }
1151        return oid.getAvailableOID();
1152    }
1153
1154    public void makePersistent(final Object JavaDoc o) {
1155        try {
1156            if (o == null) {
1157                throw BindingSupportImpl.getInstance().invalidOperation(
1158                        "makePersistent called with null object");
1159            }
1160            checkActiveTx();
1161            PCStateMan root = txDirtyListHead;
1162            makeReachablePersistent(o);
1163            if (root == null) {
1164                root = txDirtyListTail;
1165            } else {
1166                root = root.next;
1167            }
1168
1169            for (; root != null; root = root.next) root.addRefs();
1170        } catch (Exception JavaDoc e) {
1171            handleException(e);
1172        }
1173    }
1174
1175    /**
1176     * Make an instance found in a reachability search persistent. This skips
1177     * some checks done by makePersistent for speed. Note that this does not
1178     * add reachable instances.<p>
1179     */

1180    public void makeReachablePersistent(final Object JavaDoc o) {
1181        if (o == null) return;
1182        PersistenceCapable pc = checkPersCapable(o);
1183        PersistenceManager pm = pc.jdoGetPersistenceManager();
1184        if (pm == null) {
1185            reManage(pc, assignOID(pc), false);
1186        } else {
1187            PMProxy pmProxy = (PMProxy)pm;
1188            if (pmProxy.getRealPM() != this) {
1189                throw BindingSupportImpl.getInstance().invalidOperation("Object is managed by " + pm + " (this is " + proxy + "): " +
1190                        pc.getClass() + ": " + Utils.toString(pc));
1191            }
1192        }
1193    }
1194
1195    public void makePersistentAll(final Object JavaDoc[] pcs) {
1196        try {
1197            ArrayList failed = null;
1198            for (int i = 0; i < pcs.length; i++) {
1199                Object JavaDoc pc = pcs[i];
1200                try {
1201                    makePersistent(pc);
1202                } catch (RuntimeException JavaDoc e) {
1203                    if (BindingSupportImpl.getInstance().isOwnException(e)) {
1204                        if (BindingSupportImpl.getInstance().getFailedObject(e) == null) {
1205                            e = BindingSupportImpl.getInstance().exception(
1206                                    e.getMessage(), e, pc);
1207                        }
1208                        if (failed == null) failed = new ArrayList();
1209                        failed.add(e);
1210                    } else {
1211                        throw e;
1212                    }
1213                }
1214            }
1215            if (failed != null) {
1216                int n = failed.size();
1217                if (n == 1) {
1218                    throw (Exception JavaDoc)failed.get(0);
1219                } else {
1220                    Throwable JavaDoc[] a = new Throwable JavaDoc[n];
1221                    failed.toArray(a);
1222                    throw BindingSupportImpl.getInstance().exception(
1223                            n + " instances failed to persist",
1224                            a);
1225                }
1226            }
1227        } catch (Exception JavaDoc e) {
1228            handleException(e);
1229        }
1230    }
1231
1232    public void makePersistentAll(final Collection pcs) {
1233        try {
1234            ArrayList failed = null;
1235            for (Iterator i = pcs.iterator(); i.hasNext();) {
1236                Object JavaDoc pc = i.next();
1237                try {
1238                    makePersistent(pc);
1239                } catch (RuntimeException JavaDoc e) {
1240                    if (BindingSupportImpl.getInstance().isOwnException(e)) {
1241                        if (BindingSupportImpl.getInstance().getFailedObject(e) == null) {
1242                            e = BindingSupportImpl.getInstance().exception(
1243                                    e.getMessage(), e, pc);
1244                        }
1245                        if (failed == null) failed = new ArrayList();
1246                        failed.add(e);
1247                    } else {
1248                        throw e;
1249                    }
1250                }
1251            }
1252            if (failed != null) {
1253                int n = failed.size();
1254                if (n == 1) {
1255                    throw (Exception JavaDoc)failed.get(0);
1256                } else {
1257                    Throwable JavaDoc[] a = new Throwable JavaDoc[n];
1258                    failed.toArray(a);
1259                    throw BindingSupportImpl.getInstance().exception(
1260                            n + " instances failed to persist",
1261                            a);
1262                }
1263            }
1264        } catch (Exception JavaDoc e) {
1265            handleException(e);
1266        }
1267    }
1268
1269    /**
1270     * @param pcs
1271     */

1272    public void deletePersistentAll(Object JavaDoc[] pcs) {
1273        try {
1274            for (int i = 0; i < pcs.length; i++) {
1275                deletePersistent(pcs[i]);
1276            }
1277        } catch (Exception JavaDoc e) {
1278            handleException(e);
1279        }
1280    }
1281
1282    /**
1283     * @param pc
1284     */

1285    public void deletePersistent(Object JavaDoc pc) {
1286        checkActiveTx();
1287        if (isTransient(pc)) {
1288            throw BindingSupportImpl.getInstance().invalidOperation(
1289                    "The instance is transient");
1290        }
1291        try {
1292            pmPreCheck(pc).deletePersistent();
1293        } catch (Exception JavaDoc e) {
1294            handleException(e);
1295        }
1296    }
1297
1298    /**
1299     * @param pcs
1300     */

1301    public void deletePersistentAll(Collection pcs) {
1302        try {
1303            for (Iterator iterator = pcs.iterator(); iterator.hasNext();) {
1304                deletePersistent(iterator.next());
1305            }
1306        } catch (Exception JavaDoc e) {
1307            handleException(e);
1308        }
1309    }
1310
1311    /**
1312     * TODO: Remove the instance from the weak caches.
1313     *
1314     * @param pc
1315     */

1316    public void makeTransient(Object JavaDoc pc) {
1317        checkPersCapable(pc);
1318        try {
1319            if (isTransient(pc)) {
1320                //the instance is already transient.
1321
return;
1322            }
1323            pmPreCheck(pc).makeTransient();
1324        } catch (Exception JavaDoc e) {
1325            handleException(e);
1326        }
1327    }
1328
1329    public void makeTransientRecursive(Object JavaDoc pc) {
1330        checkPersCapable(pc);
1331        try {
1332            if (isTransient(pc)) {
1333                //the instance is already transient.
1334
return;
1335            }
1336            pmPreCheck(pc).makeTransientRecursive();
1337        } catch (Exception JavaDoc e) {
1338            handleException(e);
1339        }
1340    }
1341
1342    /**
1343     * TODO: Remove the instance from the weak caches.
1344     *
1345     * @param pcs
1346     */

1347    public void makeTransientAll(Object JavaDoc[] pcs) {
1348        try {
1349            Map failed = new HashMap();
1350            for (int i = 0; i < pcs.length; i++) {
1351                Object JavaDoc pc = pcs[i];
1352                try {
1353                    makeTransient(pc);
1354                } catch (Exception JavaDoc e) {
1355                    failed.put(pc, e);
1356                }
1357            }
1358            if (failed.size() > 0) {
1359                throw BindingSupportImpl.getInstance().invalidOperation(
1360                        "Errors occured with makeTransientAll: " + failed);
1361            }
1362        } catch (RuntimeException JavaDoc e) {
1363            handleException(e);
1364        }
1365    }
1366
1367    /**
1368     * TODO: Remove the instance from the weak caches.
1369     *
1370     * @param pcs
1371     */

1372    public void makeTransientAll(Collection pcs) {
1373        try {
1374            if (pcs == null) return;
1375            makeTransientAll(pcs.toArray());
1376        } catch (Exception JavaDoc e) {
1377            handleException(e);
1378        }
1379    }
1380
1381    private final boolean isTransient(Object JavaDoc pc) {
1382        if (JDOHelper.getPersistenceManager(pc) == null) {
1383            return true;
1384        }
1385        return false;
1386    }
1387
1388    public void makeTransactional(Object JavaDoc pc) {
1389        try {
1390            if (JDOHelper.getPersistenceManager(pc) == null) {
1391                //this is a transient instance
1392
reManage((PersistenceCapable)pc,
1393                        assignOID((PersistenceCapable)pc), true);
1394            }
1395            PCStateMan pcStateObject = pmPreCheck(pc);
1396            pcStateObject.makeTransactional();
1397        } catch (Exception JavaDoc e) {
1398            handleException(e);
1399        }
1400    }
1401
1402    public void makeTransactionalAll(Object JavaDoc[] pcs) {
1403        if (pcs == null) return;
1404        try {
1405            Map failed = new HashMap(pcs.length);
1406            for (int i = 0; i < pcs.length; i++) {
1407                Object JavaDoc pc = pcs[i];
1408                try {
1409                    makeTransactional(pc);
1410                } catch (Exception JavaDoc e) {
1411                    failed.put(pc, e);
1412                }
1413            }
1414            if (failed.size() > 0) {
1415                throw BindingSupportImpl.getInstance().invalidOperation(
1416                        "Errors occured with makePersistentAll:" + failed);
1417            }
1418        } catch (RuntimeException JavaDoc e) {
1419            handleException(e);
1420        }
1421    }
1422
1423    public void makeTransactionalAll(Collection pcs) {
1424        if (pcs == null) return;
1425        try {
1426            makeTransactionalAll(pcs.toArray());
1427        } catch (Exception JavaDoc e) {
1428            handleException(e);
1429        }
1430    }
1431
1432    private final void makeNonTransactionalImp(Object JavaDoc pc) {
1433        PCStateMan pcStateObject = pmPreCheck(pc);
1434        pcStateObject.makeNonTransactional();
1435    }
1436
1437    public void makeNontransactional(Object JavaDoc pc) {
1438        try {
1439            makeNonTransactionalImp(pc);
1440        } catch (Exception JavaDoc e) {
1441            handleException(e);
1442        }
1443    }
1444
1445    public void makeNontransactionalAll(Object JavaDoc[] pcs) {
1446        try {
1447            for (int i = 0; i < pcs.length; i++) {
1448                makeNonTransactionalImp(pcs[i]);
1449            }
1450        } catch (Exception JavaDoc e) {
1451            handleException(e);
1452        }
1453    }
1454
1455    public void makeNontransactionalAll(Collection pcs) {
1456        for (Iterator iterator = pcs.iterator(); iterator.hasNext();) {
1457            makeNonTransactionalImp(iterator.next());
1458        }
1459    }
1460
1461    public void setUserObject(Object JavaDoc o) {
1462        try {
1463            sm.setUserObject(userObject = o);
1464        } catch (Exception JavaDoc e) {
1465            handleException(e);
1466        }
1467    }
1468
1469    public Object JavaDoc getUserObject() {
1470        return userObject;
1471    }
1472
1473    public PersistenceManagerFactory getPersistenceManagerFactory() {
1474        return pmf;
1475    }
1476
1477    public void setMultithreaded(boolean flag) {
1478        // Changing from multithreaded false to true is not allowed. This must
1479
// be done at the PMF level before the PM is created.
1480
if (flag && !multithreaded) {
1481            throw BindingSupportImpl.getInstance().invalidOperation("PM.setMultithreaded(true) is not allowed if the PM " +
1482                    "was created from a PMF with multithreaded false");
1483        }
1484        // ignore the true -> false transition as the extra synchronization
1485
// has only a performance impact
1486
}
1487
1488    public boolean getMultithreaded() {
1489        return multithreaded;
1490    }
1491
1492    public void setMultithreadedImp(boolean flag) {
1493        multithreaded = flag;
1494        createProxy();
1495    }
1496
1497    public void setIgnoreCache(boolean flag) {
1498        this.ignoreCache = flag;
1499    }
1500
1501    public boolean getIgnoreCache() {
1502        return this.ignoreCache;
1503    }
1504
1505    /**
1506     * Does a preCheck on a object claimed to be PersistanceCapable and managed by
1507     * this pm.
1508     */

1509    private final PCStateMan pmPreCheck(final Object JavaDoc pc) {
1510        return pmPreCheck(checkPersCapable(pc));
1511
1512    }
1513
1514    private PCStateMan pmPreCheck(PersistenceCapable pc) {
1515        if (!checkManagedBy(pc)) {
1516            return null;
1517        }
1518        PCStateMan pcState = getInternalSM(pc);
1519        if (Debug.DEBUG) {
1520            if (pcState == null && JDOHelper.getPersistenceManager(pc) != null) {
1521                throw BindingSupportImpl.getInstance().internal(
1522                        "The pm is set on instance but is not in weak list");
1523            }
1524        }
1525        return pcState;
1526    }
1527
1528    private final boolean checkManagedBy(PersistenceCapable pc) {
1529        PMProxy pm = (PMProxy)pc.jdoGetPersistenceManager();
1530        if (pm != null) {
1531            if (pm == proxy) return true;
1532            throw BindingSupportImpl.getInstance().invalidOperation("Object is managed by " + pm + " (this is " + proxy + "): " +
1533                    pc.getClass() + ": " + Utils.toString(pc));
1534        }
1535        return false;
1536    }
1537
1538    private final void checkActiveTx() {
1539        if (!isActive()) {
1540            throw BindingSupportImpl.getInstance().invalidOperation(
1541                    "No active transaction.");
1542        }
1543    }
1544
1545    public void begin() {
1546        if (managed) {
1547            throw BindingSupportImpl.getInstance().invalidOperation(
1548                    "May not call begin in managed transaction environment");
1549        }
1550        beginImp();
1551    }
1552
1553    private void beginImp() {
1554        if (transactionActive) {
1555            throw BindingSupportImpl.getInstance().invalidOperation(
1556                    "The transaction is already active");
1557        }
1558        try {
1559            transactionActive = true;
1560            sm.begin(optimistic);
1561            if (!optimistic && !interceptDfgFieldAccess) {
1562                cache.setInterceptDfgFieldAccess(true);
1563            }
1564        } catch (Exception JavaDoc e) {
1565            handleException(e);
1566        }
1567    }
1568
1569    /**
1570     * This is for client to rollback the connection. This will try to
1571     * orderly rollback the data. The pm will be reset if an internal exception
1572     * happens during rollback. The pm must be reset as new to avoid inconsistent behaviour.
1573     * <p/>
1574     * NB
1575     * TODO ensure that all tx instances are rolledback properly.
1576     * If for instance the are already removed out of the tx list at commit
1577     * time then they can not undergo a rollback.
1578     */

1579    public void rollback() {
1580        if (Debug.DEBUG) {
1581            System.out.println(
1582                    ">>>>>>>>>>> JdoGeniePersistenceManagerImp.rollback <<<<<<<<<<<<<<<");
1583        }
1584        if (managed) {
1585            throw BindingSupportImpl.getInstance().invalidOperation(
1586                    "May not call rollback in managed transaction environment");
1587        }
1588        rollbackImp();
1589    }
1590
1591    /**
1592     * Reset this PM after an internal error of some kind. This just flags
1593     * it to not go back in the pool.
1594     */

1595    private void fatalReset() {
1596        mustNotPool = true;
1597    }
1598
1599    /**
1600     * This is called by JDOConnectionImpProxy when it handles a
1601     * JDOFatalException from a call to the JDOConnection.
1602     */

1603    public void rollbackForFatalExceptionInJDOConnectionProxy() {
1604        if (managed || !transactionActive) return;
1605        rollbackImp();
1606    }
1607
1608    /**
1609     * This is an orderly rollback.
1610     */

1611    private void rollbackImp() {
1612        if (busyWithRollback) return;
1613        checkActiveTx();
1614        resetEpcFields();
1615        try {
1616            busyWithRollback = true;
1617
1618            if (synchronizationInstance != null) {
1619                synchronizationInstance.afterCompletion(
1620                        Status.STATUS_ROLLING_BACK);
1621            }
1622
1623            try {
1624                cache.doRollback(retainValues);
1625                sm.rollback();
1626            } finally {
1627                reset();
1628            }
1629
1630            if (synchronizationInstance != null) {
1631                synchronizationInstance.afterCompletion(
1632                        Status.STATUS_ROLLEDBACK);
1633            }
1634
1635        } catch (Exception JavaDoc e) {
1636            fatalReset();
1637            if (BindingSupportImpl.getInstance().isOwnException(e)) {
1638                throw (RuntimeException JavaDoc)e;
1639            } else {
1640                throw BindingSupportImpl.getInstance().internal(e.getMessage(),
1641                        e);
1642            }
1643        } finally {
1644            transactionActive = false;
1645            busyWithRollback = false;
1646        }
1647    }
1648
1649    public void setRestoreValues(boolean b) {
1650        checkPropChange();
1651        this.restoreValues = b;
1652    }
1653
1654    public boolean getRestoreValues() {
1655        return restoreValues;
1656    }
1657
1658    /**
1659     * Check the consistency of all instances in the local cache. Currently
1660     * this makes sure that all birectional relationships have been completed
1661     * properly (both sides in sync) but other checks may will be added in
1662     * future. This method is very slow and should only be used for debugging
1663     * during development.
1664     *
1665     * @see #setCheckModelConsistencyOnCommit(boolean)
1666     */

1667    public void checkModelConsistency() {
1668        cache.checkModelConsistency();
1669    }
1670
1671    /**
1672     * Add the OID and State for deletion.
1673     */

1674    public void addForDelete(OID oid, State state) {
1675        if (Debug.DEBUG) {
1676            // make sure untyped OIDs are not added
1677
if (oid.getAvailableClassMetaData() == null) {
1678                BindingSupportImpl.getInstance().internal("oid is untyped: " +
1679                        oid);
1680            }
1681        }
1682        toBeDeleted.add(oid, state);
1683    }
1684
1685    /**
1686     * This calls commit on all the transactional objects. It ensures
1687     * that the instances undergo the correct state changes.
1688     */

1689    public void commit() {
1690        if (managed) {
1691            throw BindingSupportImpl.getInstance().invalidOperation(
1692                    "May not call commit in managed transaction environment");
1693        }
1694        if (!transactionActive) {
1695            throw BindingSupportImpl.getInstance().invalidOperation(
1696                    "Transaction is not active");
1697        }
1698        internalCommit(false);
1699    }
1700
1701    private void dumpTxDirtyList(String JavaDoc msg) {
1702        System.out.println("--- txDirtyListHead: " + msg);
1703        for (PCStateMan o = txDirtyListTail; o != null; o = o.next) {
1704            System.out.println(o.pc.getClass().getName() + "@" +
1705                    Integer.toHexString(System.identityHashCode(o.pc)) +
1706                    ": " + o.pc);
1707        }
1708        System.out.println("---");
1709    }
1710
1711    private void internalCommit(boolean phase) {
1712        StatesReturned sc = null;
1713
1714        if (synchronizationInstance != null) {
1715            synchronizationInstance.beforeCompletion();
1716            synchronizationInstance.afterCompletion(Status.STATUS_COMMITTING);
1717        }
1718
1719        try {
1720            prepareForStore(true);
1721
1722            sc = sm.store(storeOidStateContainer, toBeDeleted, retainValues,
1723                    phase
1724                        ? StorageManager.STORE_OPTION_PREPARE
1725                        : StorageManager.STORE_OPTION_COMMIT,
1726                    false);
1727
1728            resetEpcFields();
1729            updateOIDsAndDoAutoS(sc);
1730            cache.doCommit(retainValues);
1731
1732            invokePostStore();
1733
1734            if (!phase) {
1735
1736                if (synchronizationInstance != null) {
1737                    synchronizationInstance.afterCompletion(
1738                            Status.STATUS_COMMITTED);
1739                }
1740
1741            }
1742
1743            reset();
1744            transactionActive = false;
1745        } catch (Exception JavaDoc e) {
1746            handleException(e);
1747        } finally {
1748            if (sc != null) {
1749                sc.clear();
1750            }
1751        }
1752    }
1753
1754    /**
1755     * Prepare to store all dirty instances for a commit or flush. This finds
1756     * all reachable instances and invokes preStore lifecycle listeners and
1757     * jdoPreStore instance callbacks.
1758     */

1759    private void prepareForStore(boolean commit) {
1760        boolean preStoreCalled = false;
1761        for (PCStateMan i = txDirtyListTail; i != null; i = i.next) {
1762
1763            i.addRefs();
1764            preStoreCalled |= i.doJDOPreStore(listeners);
1765        }
1766        for (; preStoreCalled;) {
1767            PCStateMan root = txDirtyListHead;
1768            for (PCStateMan i = txDirtyListTail; i != null; i = i.next) {
1769
1770                i.addRefs();
1771            }
1772            if (root == txDirtyListHead) break;
1773            preStoreCalled = false;
1774            for (PCStateMan i = root; i != null; i = i.next) {
1775                preStoreCalled |= i.doJDOPreStore(listeners);
1776            }
1777        }
1778
1779        storeOidStateContainer.clear();
1780        toBeDeleted.clear();
1781        for (PCStateMan i = txDirtyListTail; i != null; i = i.next) {
1782            i.prepareCommitOrFlush(commit);
1783        }
1784        if (checkModelConsistencyOnCommit) {
1785            checkModelConsistency();
1786        }
1787
1788        if (commit) { // fill in the epc stuff
1789
storeOidStateContainer.epcAll = epcAll;
1790            storeOidStateContainer.epcOids = epcObjectCount > 0
1791                    ? modelMetaData.convertToOID(epcObjects, epcObjectCount)
1792                    : null;
1793            storeOidStateContainer.epcClasses = epcClasses;
1794            storeOidStateContainer.epcClassCount = epcClassCount;
1795        }
1796    }
1797
1798    private void invokePostStore() {
1799        if (listeners != null && listeners.hasPostStoreListeners()) {
1800            for (PCStateMan i = txDirtyListTail; i != null; i = i.next) {
1801                i.firePostStore(listeners);
1802            }
1803        }
1804    }
1805
1806    /**
1807     * This flushes everything to the store. After this state interogation
1808     * will not be correct and the behaviour is not inline with the spec.
1809     * This is used for big batch procedures that needs to free the memory.
1810     */

1811    public void flush() {
1812        StatesReturned sc = null;
1813        try {
1814            prepareForStore(true);
1815
1816            sc = sm.store(storeOidStateContainer, toBeDeleted,
1817                    false, StorageManager.STORE_OPTION_FLUSH, true);
1818
1819            updateOIDsAndDoAutoS(sc);
1820
1821            cache.doCommit(retainValues);
1822
1823            invokePostStore();
1824
1825            resetEpcFields();
1826            reset();
1827        } catch (Exception JavaDoc x) {
1828            handleException(x);
1829        } finally {
1830            if (sc != null) {
1831                sc.clear();
1832            }
1833        }
1834    }
1835
1836    public void flush(boolean retainValues) {
1837        if (retainValues) {
1838            flushRetainState();
1839        } else {
1840            flush();
1841        }
1842    }
1843
1844    public List versantAllDirtyInstances() {
1845        if (txDirtyListTail == null) return Collections.EMPTY_LIST;
1846        List l = new ArrayList();
1847        for (PCStateMan i = txDirtyListTail; i != null; i = i.next) {
1848            l.add(i.pc);
1849        }
1850        return l;
1851    }
1852
1853    /**
1854     * This is used to flush the current changes to the store.
1855     * All state interogation will still work after this is called.
1856     * The data is just flushed to the store for queries to work.
1857     * <p/>
1858     * The implication of this is that the datastore connection will be pinned
1859     * to the jdoConnection for the life time of the transaction.
1860     * <p/>
1861     * This method will be a no-op if the transaction is not active.
1862     */

1863    public void flushRetainState() {
1864        if (!transactionActive) return;
1865        StatesReturned sc = null;
1866
1867        storeOidStateContainer.clear();
1868        toBeDeleted.clear();
1869        try {
1870            prepareForStore(false);
1871
1872            if (storeOidStateContainer.isEmpty() && toBeDeleted.size() == 0) {
1873                return;
1874            }
1875
1876            sc = sm.store(storeOidStateContainer, toBeDeleted, true,
1877                    StorageManager.STORE_OPTION_FLUSH, false);
1878
1879            updateOIDsAndDoAutoS(sc);
1880            for (PCStateMan i = txDirtyListTail; i != null; i = i.next) {
1881                i.flushCommit();
1882            }
1883
1884            invokePostStore();
1885
1886            storeOidStateContainer.clear();
1887            toBeDeleted.clear();
1888        } catch (Exception JavaDoc x) {
1889            handleException(x);
1890        } finally {
1891            try {
1892                sc.clear();
1893            } catch (Exception JavaDoc e) {
1894                //ignore
1895
}
1896        }
1897    }
1898
1899    /**
1900     * This will do everything except actually commit to the store.
1901     */

1902    public void phaseCommit1() {
1903        internalCommit(true);
1904    }
1905
1906    /**
1907     * Do the actual commit on the store.
1908     */

1909    public void phaseCommit2() {
1910        sm.commit();
1911
1912        if (synchronizationInstance != null) {
1913            synchronizationInstance.afterCompletion(Status.STATUS_COMMITTED);
1914        }
1915
1916    }
1917
1918    public boolean isActive() {
1919        return transactionActive;
1920    }
1921
1922    public final boolean isActiveDS() {
1923        return transactionActive && !optimistic;
1924    }
1925
1926    public void setNontransactionalRead(boolean nontransactionalRead) {
1927        checkPropChange();
1928        this.nontransactionalRead = nontransactionalRead;
1929    }
1930
1931    public boolean getNontransactionalRead() {
1932        return nontransactionalRead;
1933    }
1934
1935    public void setNontransactionalWrite(boolean nontransactionalWrite) {
1936        checkPropChange();
1937        this.nontransactionalWrite = nontransactionalWrite;
1938    }
1939
1940    public boolean getNontransactionalWrite() {
1941        return nontransactionalWrite;
1942    }
1943
1944    public void setRetainValues(boolean retainValues) {
1945// checkPropChange();
1946
this.retainValues = retainValues;
1947    }
1948
1949    /**
1950     * Check for changing props in active tx.
1951     */

1952    private final void checkPropChange() {
1953        if (transactionActive) {
1954            throw BindingSupportImpl.getInstance().invalidOperation(
1955                    "May not be changed in active transaction");
1956        }
1957    }
1958
1959    public boolean getRetainValues() {
1960        return retainValues;
1961    }
1962
1963    public void setOptimistic(boolean optimistic) {
1964        checkPropChange();
1965        this.optimistic = optimistic;
1966    }
1967
1968    public boolean getOptimistic() {
1969        return optimistic;
1970    }
1971
1972
1973    public void setSynchronization(Synchronization JavaDoc sync) {
1974        this.synchronizationInstance = sync;
1975    }
1976
1977    public Synchronization JavaDoc getSynchronization() {
1978        return synchronizationInstance;
1979    }
1980
1981
1982    public PersistenceManager getPersistenceManager() {
1983        return VersantPersistenceManagerImp.this;
1984    }
1985
1986//==================================Transaction imp end=======================
1987

1988
1989    /**
1990     * Create a new oid for a pc instance.
1991     */

1992    private NewObjectOID assignOID(PersistenceCapable pc) {
1993        ClassMetaData cmd = modelMetaData.getClassMetaData(pc.getClass());
1994        if (cmd == null) {
1995            throw BindingSupportImpl.getInstance().invalidOperation(
1996                    "There is no metadata registered for " + pc.getClass());
1997        }
1998        if (cmd.instancesNotAllowed) {
1999            throw BindingSupportImpl.getInstance().invalidOperation(
2000                    "Instances of " + cmd.qname + " may not be persistent or managed");
2001        }
2002        NewObjectOID oid = cmd.createNewObjectOID();
2003        oid.init(++counter);
2004        return oid;
2005    }
2006
2007    /**
2008     * This is called by the JDOManagedCache when an instance is added
2009     * but it is not already managed.
2010     */

2011    public PCStateMan reManage(OID oid, State state) {
2012        if (oid.getAvailableClassMetaData() == null) {
2013            // replace untyped OID with a real one since we have a state
2014
OID tmp = state.getClassMetaData(modelMetaData).createOID(true);
2015            tmp.setLongPrimaryKey(oid.getLongPrimaryKey());
2016            oid = tmp;
2017        }
2018        PCStateMan stateObject = getStateObject();
2019        stateObject.init(oid, state.getClassMetaData(modelMetaData), state, this);
2020        return stateObject;
2021    }
2022
2023    private final void reManage(PersistenceCapable pc, OID oid,
2024            boolean isTransactional) {
2025        PCStateMan sm = getStateObject();
2026        pc.jdoReplaceStateManager(createStateManagerProxy(sm));
2027        sm.init(pc, oid, isTransactional);
2028        sm.getRealOIDIfAppId();
2029
2030        // check for app identity instance with same pk as instance already in
2031
// local pm cache
2032
if (!isTransactional
2033                && sm.getClassMetaData().identityType == MDStatics.IDENTITY_TYPE_APPLICATION) {
2034            OID realOID = ((NewObjectOID)sm.oid).realOID;
2035            if (realOID != null && cache.contains(realOID)) {
2036
2037                // throwing duplicateKey would be problematic for
2038
// java, because duplicateKey is fatal
2039
throw BindingSupportImpl.getInstance().
2040                        runtime("Instance of " + sm.getClassMetaData().qname +
2041                        " with identity '" + realOID + "' already exists in" +
2042                        " the local PM cache");
2043
2044
2045
2046            }
2047        }
2048
2049        //The refs to the wrapper is kept around to avoid gc of the instance
2050
cache.add(sm);
2051        if (Debug.DEBUG) {
2052            if (sm.cacheEntry == null) {
2053                throw BindingSupportImpl.getInstance().internal(
2054                        "cacheEntry must be initialized");
2055            }
2056        }
2057    }
2058
2059    /**
2060     * Create a proxy for a PCStateMan or return it as is if no proxy is
2061     * needed. This is used to synchronize StateManager access when
2062     * multithreading is required.
2063     */

2064    public StateManager createStateManagerProxy(PCStateMan sm) {
2065        if (multithreaded) {
2066            return new SynchronizedStateManagerProxy(proxy, sm);
2067        } else {
2068            return sm;
2069        }
2070    }
2071
2072    /**
2073     * add an transactional instance to the list.
2074     *
2075     * @param stateObject
2076     */

2077    public void addTxStateObject(PCStateMan stateObject) {
2078        if (Debug.DEBUG) {
2079            if (!stateObject.isTx()) {
2080                throw BindingSupportImpl.getInstance().internal(
2081                        "The instance is not Transactional");
2082            }
2083        }
2084
2085        if (stateObject.isDirty()) {
2086            if (!stateObject.isInDirtyList(txDirtyListHead)) {
2087                addTxDirty(stateObject);
2088            }
2089        } else {
2090            if (stateObject.isInDirtyList(txDirtyListHead)) {
2091                removeTxDirty(stateObject);
2092            }
2093        }
2094    }
2095
2096    /**
2097     * Add pc to the dirty list.
2098     */

2099    private void addTxDirty(PCStateMan pc) {
2100        if (txDirtyListHead == null) {
2101            txDirtyListHead = txDirtyListTail = pc;
2102            pc.next = null;
2103            pc.prev = null;
2104        } else {
2105            pc.prev = txDirtyListHead;
2106            txDirtyListHead.next = pc;
2107            pc.next = null;
2108            txDirtyListHead = pc;
2109        }
2110        dirtyCmdBits.add(pc.getClassMetaData());
2111        pc.inDirtyList = true;
2112    }
2113
2114    /**
2115     * Remove pc from the dirty list.
2116     */

2117    private void removeTxDirty(PCStateMan pc) {
2118        if (Debug.DEBUG) {
2119            if (!pc.isInDirtyList(txDirtyListHead)) {
2120                throw BindingSupportImpl.getInstance().internal(
2121                        "not in dirty list: " + pc);
2122            }
2123        }
2124        if (txDirtyListTail == pc) {
2125            txDirtyListTail = pc.next;
2126        } else {
2127            pc.prev.next = pc.next;
2128        }
2129        if (txDirtyListHead == pc) {
2130            txDirtyListHead = pc.prev;
2131        } else {
2132            pc.next.prev = pc.prev;
2133        }
2134        dirtyCmdBits.remove(pc.getClassMetaData());
2135    }
2136
2137    /**
2138     * Clear the dirty list.
2139     */

2140    public void clearTxDirtyList() {
2141        for (PCStateMan i = txDirtyListTail; i != null;) {
2142            PCStateMan next = i.next;
2143            i.prev = null;
2144            i.next = null;
2145            i = next;
2146            dirtyCmdBits.clear();
2147        }
2148        txDirtyListHead = txDirtyListTail = null;
2149    }
2150
2151    public void removeTxStateObject(PCStateMan stateObject) {
2152        if (stateObject.isInDirtyList(txDirtyListHead)) {
2153            removeTxDirty(stateObject);
2154        }
2155    }
2156
2157    private final void reset() {
2158        storeOidStateContainer.clear();
2159        clearTxDirtyList();
2160    }
2161
2162    /**
2163     * This will reset the pm to be returned to the pool.
2164     */

2165    public void resetForPooling() {
2166        if (Debug.DEBUG) {
2167            if (transactionActive) {
2168                throw BindingSupportImpl.getInstance().fatal(
2169                        "The tx must be inactive");
2170            }
2171        }
2172        managed = false;
2173        cache.clear();
2174        sm.reset();
2175        sm.setUserObject(userObject = null);
2176
2177        synchronizationInstance = null;
2178
2179        resetEpcFields();
2180        reset();
2181    }
2182
2183    /**
2184     * Check to see if the pm has not been closed by the user.
2185     */

2186    private void checkClosed() {
2187        checkInPool();
2188        if (closed) {
2189            throw BindingSupportImpl.getInstance().invalidOperation(
2190            
2191                    "The 'PersistenceManager' is already closed");
2192 
2193                     
2194        }
2195    }
2196
2197    public PersistenceManager getPersistenceManager(PersistenceCapable pc) {
2198        return this;
2199    }
2200
2201    private PCStateMan getStateObject() {
2202        return new PCStateMan(cache, modelMetaData, proxy);
2203    }
2204
2205// public Collection mapFrom(Object data, Class cls) {
2206
// if (data instanceof ResultSet) {
2207
// return null;
2208
// } else {
2209
// throw BindingSupportImpl.getInstance().unsupported();
2210
// }
2211
// }
2212
//
2213
// public Collection mapFrom(Object data, Class cls, String[] customMapping) {
2214
// if (data instanceof ResultSet) {
2215
// return null;
2216
// } else {
2217
// throw BindingSupportImpl.getInstance().unsupported();
2218
// }
2219
// }
2220

2221//============================debug methods ============================================================================
2222

2223    public boolean isPNonTx(Object JavaDoc pc) {
2224        return pmPreCheck(pc).isPNonTx();
2225    }
2226
2227    public boolean isPClean(Object JavaDoc pc) {
2228        return pmPreCheck(pc).isPClean();
2229    }
2230
2231    public boolean isPNew(Object JavaDoc pc) {
2232        return pmPreCheck(pc).isPNew();
2233    }
2234
2235    public boolean isPNewDeleted(Object JavaDoc pc) {
2236        return pmPreCheck(pc).isPNewDeleted();
2237    }
2238
2239    public boolean isPDeleted(Object JavaDoc pc) {
2240        return pmPreCheck(pc).isPDeleted();
2241    }
2242
2243    public boolean isTClean(Object JavaDoc pc) {
2244        return pmPreCheck(pc).isTClean();
2245    }
2246
2247    public boolean isTDirty(Object JavaDoc pc) {
2248        return pmPreCheck(pc).isTDirty();
2249    }
2250
2251    public boolean isPDirty(Object JavaDoc pc) {
2252        return pmPreCheck(pc).isPDirty();
2253    }
2254
2255    /**
2256     * Return the internal oid representation for this pc instance.
2257     * This oid is the actual oid and not a clone. If pc is null then null
2258     * is returned.
2259     */

2260    public OID getInternalOID(final PersistenceCapable pc) {
2261        if (pc == null) return null;
2262        return getInternalSM(pc).oid;
2263    }
2264
2265    /**
2266     * This is used internally to obtain the PCStateObject for a PersistanceCapable
2267     * instance. This instance must be managed by this pm.
2268     */

2269    public PCStateMan getInternalSM(final PersistenceCapable pc) {
2270        if (pc == null) return null;
2271        requestedPCState = null;
2272        pc.jdoGetPersistenceManager();
2273        if (requestedPCState == null) {
2274            throw BindingSupportImpl.getInstance().internal("Instance not managed: " +
2275                    pc.getClass().getName() + "@" +
2276                    Integer.toHexString(System.identityHashCode(pc)) + ": " +
2277                    pc.toString());
2278        }
2279        return requestedPCState;
2280    }
2281
2282    public PCStateMan getSMIfManaged(PersistenceCapable pc) {
2283        if (pc == null) return null;
2284        requestedPCState = null;
2285        pc.jdoGetPersistenceManager();
2286        return requestedPCState;
2287    }
2288
2289    /**
2290     * This is used internally to obtain the PCStateObject for a PersistanceCapable
2291     * instance. This instance must be managed by this pm.
2292     */

2293    public PCStateMan getInternalSM(OID oid) {
2294        if (oid == null) return null;
2295        return getInternalSM((PersistenceCapable)getObjectById(oid, false));
2296    }
2297
2298    /**
2299     * This is used for debug. Not to be used else where.
2300     */

2301    public State getInternaleState(PersistenceCapable pc) {
2302        PCStateMan pcState = getInternalSM(pc);
2303        if (pcState == null) return null;
2304        return pcState.state;
2305    }
2306
2307    public void dump(OID oid) {
2308        if (Debug.DEBUG) {
2309            PCStateMan pcStateObject = cache.getByOID(oid, true);
2310            if (pcStateObject != null) {
2311                pcStateObject.dump();
2312            } else {
2313                if (Debug.DEBUG) {
2314                    Debug.OUT.println("######## null for dump#######");
2315                }
2316            }
2317        }
2318    }
2319
2320    /**
2321     * Are there any dirty instances?
2322     */

2323    public boolean isDirty() {
2324        return txDirtyListHead != null;
2325    }
2326
2327    /**
2328     * This is used from getObjectByID where the object by id is not in the managed cache.
2329     * If there there is no jdo instance for the supplied instance then null is returned.
2330     *
2331     * @param ignoreLocalPmCache This is used to indicate that we should not check the
2332     * if the state is in the localCache on the serverside. The serverSide might
2333     * have a ref to the local cache.
2334     */

2335    private PCStateMan getStateMan(OID aOID, int fgIndex, int fieldNo,
2336            int navClassIndex, boolean ignoreLocalPmCache) {
2337        StatesReturned container = null;
2338        try {
2339            container = getStateJdoConnection(aOID, null, fgIndex,
2340                    aOID.getAvailableClassId(),
2341                    ignoreLocalPmCache, fieldNo, navClassIndex);
2342
2343            if (Debug.DEBUG) {
2344                if (container.get(container.getDirectOID()) == NULLState.NULL_STATE) {
2345                    //this instance does not exist in db
2346
if (container.size() != 1) {
2347                        throw BindingSupportImpl.getInstance().internal("Then directOid of the container is null " +
2348                                "so there should not be any other instances");
2349                    }
2350                }
2351            }
2352
2353            return addAndReturnFirstDirect(container);
2354        } finally {
2355            if (container != null) container.clear();
2356        }
2357    }
2358
2359    /**
2360     * This translates the old JDOConnection style call into a StorageManager
2361     * call. It should be nuked at some point.
2362     */

2363    private StatesReturned getStateJdoConnection(OID oid, State current,
2364            int fetchGroup, int classId, boolean ignoreLocalPmCache,
2365            int fieldNo, int navClassIndex) {
2366        // todo use ignoreLocalPmCache to modify context
2367

2368        if (classId < 0) classId = oid.getAvailableClassId();
2369        ClassMetaData cmd = oid.getAvailableClassMetaData();
2370        FetchGroup fg = cmd == null ? null : cmd.getFetchGroup(fetchGroup, classId);
2371
2372        FieldMetaData triggerField;
2373        if (navClassIndex >= 0) { // navigated stateFieldNo
2374
ClassMetaData navCmd = modelMetaData.classes[navClassIndex];
2375            triggerField = navCmd.stateFields[fieldNo];
2376        } else if (fieldNo >= 0 && cmd != null) { // missing absFieldNo
2377
triggerField = cmd.stateFields[cmd.absToRel[fieldNo]];
2378        } else {
2379            triggerField = null;
2380        }
2381
2382        return sm.fetch(this, oid, current, fg, triggerField);
2383    }
2384
2385    /**
2386     * This is called by sm's if they require a field. This will update the
2387     * local cache with the requested data (State instances). The returned
2388     * container reference must be kept until all the required State instances
2389     * in the local cache have been referenced or they might be GCed.
2390     * This is important for collections of PC and other fields that
2391     * involve fetching State instances and loading them into the local cache.
2392     * They are only hard referenced when the SCO instance has been created.
2393     */

2394    public StatesReturned getState(OID oid, State current, int fgi, int fieldNo,
2395        int navClassIndex, boolean ignoreLocalPmCache) {
2396        StatesReturned container = getStateJdoConnection(oid,
2397                current == null || current.isEmpty() ? null : current,
2398                fgi, oid.getAvailableClassId(),
2399                ignoreLocalPmCache, fieldNo, navClassIndex);
2400
2401        if (Debug.DEBUG) {
2402            if (container.get(container.getDirectOID()) == NULLState.NULL_STATE) {
2403                //this instance does not exist in db
2404
if (container.size() != 1) {
2405                    throw BindingSupportImpl.getInstance().internal("Then directOid of the container is null " +
2406                            "so there should not be any other instances");
2407                }
2408            }
2409        }
2410        addToCache(container);
2411        return container;
2412    }
2413
2414    /**
2415     * This is called by sm's when doing a refresh. It will ensure that the
2416     * data comes from the database when in a datastore transaction.
2417     */

2418    public void getStateForRefresh(OID oid, State current, int fgi) {
2419        StatesReturned container = null;
2420        try {
2421            container = getStateJdoConnection(oid,
2422                    current == null || current.isEmpty() ? null : current,
2423                    fgi, oid.getAvailableClassId(), true,
2424                    -1, -1);
2425            addToCache(container);
2426        } finally {
2427            if (container != null) container.clear();
2428        }
2429    }
2430
2431    private void fillCacheWith(OIDArray oids, int fgi, int stateFieldNo,
2432            int navClassIndex) {
2433        StatesReturned container = null;
2434        try {
2435            FieldMetaData triggerField;
2436            if (navClassIndex >= 0) { // navigated stateFieldNo
2437
ClassMetaData navCmd = modelMetaData.classes[navClassIndex];
2438                triggerField = navCmd.stateFields[stateFieldNo];
2439            } else {
2440                triggerField = null;
2441            }
2442            container = sm.fetch(this, oids, triggerField);
2443            addToCache(container);
2444        } finally {
2445            if (container != null) container.clear();
2446        }
2447    }
2448
2449    /**
2450     * This is the pm is not the current PM.
2451     */

2452    private static final void checkPM(PersistenceManager otherPM,
2453            PersistenceManager currentPM) {
2454        if (otherPM != null && otherPM != currentPM) {
2455            throw BindingSupportImpl.getInstance().invalidOperation(
2456                    "The instance is not managed by this PersistenceManager");
2457        }
2458    }
2459
2460    private static final PersistenceCapable checkPersCapable(Object JavaDoc o) {
2461        try {
2462            return (PersistenceCapable)o;
2463        } catch (ClassCastException JavaDoc e) {
2464            throw BindingSupportImpl.getInstance().invalidOperation("The supplied instance is not of type " +
2465                    PersistenceCapable.class.getName() +
2466                    " (" + o.getClass().getName() + ")");
2467        }
2468    }
2469
2470    /**
2471     * <<<<<<< VersantPersistenceManagerImp.java
2472     * This util method is used by collection types to preload their pc
2473     * entries. It tests to determine if the states refered to by the oids is
2474     * in the managed cache. If not they must be bulk loaded from server.
2475     * The scenario in which this is likely to happen is when the collection
2476     * is not in the default fetch group and the state is in cache with the
2477     * collection filled in. If this collection field is read then the
2478     * pcstateman will determine that the stateField is filled and hence not
2479     * ask the server for it.
2480     */

2481    public void checkToPreFetch(Object JavaDoc[] oids, int stateFieldNo,
2482            int navClassIndex) {
2483        if (oids != null && oids.length > 0 && oids[0] != null
2484                && cache.getByOID((OID)oids[0], true) == null) {
2485            OIDArray oidArray = new OIDArray();
2486            for (int i = 0; i < oids.length && oids[i] != null; i++) {
2487                oidArray.add((OID)oids[i]);
2488            }
2489            fillCacheWith(oidArray, 0, stateFieldNo, navClassIndex);
2490        }
2491    }
2492
2493    /**
2494     * This does general exception handling. It ensures that a rollback
2495     * is done for Fatal exceptions.
2496     * CR:
2497     * If called with an instance of JDOUserException it's a no-op
2498     * and the passed instance is thrown.
2499     */

2500    private final void handleException(Exception JavaDoc x) {
2501        if (BindingSupportImpl.getInstance().isOwnFatalException(x) && isActive()) {
2502            try {
2503                rollbackImp();
2504            } catch (Exception JavaDoc e) {
2505                // discard as we are already busy processing an earlier
2506
// exception
2507
}
2508        }
2509        if (BindingSupportImpl.getInstance().isOwnInternalException(x)) {
2510            fatalReset();
2511            throw (RuntimeException JavaDoc)x;
2512        } else if (BindingSupportImpl.getInstance().isOwnException(x)) {
2513            throw (RuntimeException JavaDoc)x;
2514        } else {
2515            fatalReset();
2516            throw BindingSupportImpl.getInstance().internal(x.getMessage(), x);
2517        }
2518    }
2519
2520    /**
2521     * Convert all PC, VersantOid and objectid-class params to OIDs. This
2522     * makes it possible to pass an OID instead of a PC instance for PC
2523     * parameters.
2524     */

2525    public void convertPcParamsToOID(Object JavaDoc[] params) {
2526        if (params == null) return;
2527        int n = params.length;
2528        for (int i = 0; i < n; i++) {
2529            Object JavaDoc param = params[i];
2530            if (param == null) continue;
2531            if (param instanceof Collection) {
2532                List l = new ArrayList((Collection)param);
2533                for (int j = 0; j < l.size(); j++) {
2534                    Object JavaDoc o = (Object JavaDoc)l.get(j);
2535                    o = convertPcParamsToOIDImp(o, i);
2536                    if (o instanceof OID) {
2537                        l.set(j, o);
2538                    }
2539                }
2540                params[i] = l;
2541            } else {
2542                params[i] = convertPcParamsToOIDImp(param, i);
2543            }
2544        }
2545    }
2546
2547    private Object JavaDoc convertPcParamsToOIDImp(Object JavaDoc param, int paramIndex) {
2548        if (param == null) return param;
2549        if (param instanceof PersistenceCapable) {
2550            PersistenceCapable pc = (PersistenceCapable)param;
2551            if (pc.jdoGetPersistenceManager() != proxy) {
2552                if (pc.jdoGetPersistenceManager() != null) {
2553                    throw BindingSupportImpl.getInstance().invalidOperation("PC parameter " + paramIndex + " is managed by " + pc.jdoGetPersistenceManager() +
2554                            " (this is " + proxy + "): " +
2555                            pc.getClass() + ": " + Utils.toString(pc));
2556                } else {
2557                    throw BindingSupportImpl.getInstance().invalidOperation("PC parameter " + paramIndex + " is transient: " +
2558                            pc.getClass() + ": " + Utils.toString(pc));
2559                }
2560            }
2561            param = getInternalOID((PersistenceCapable)param);
2562        } else if (param instanceof VersantOid) {
2563            // datastore identity OID parameter
2564
OID oid = modelMetaData.convertJDOGenieOIDtoOID((VersantOid)param);
2565            param = convertNewToActual(oid);
2566        } else {
2567            ClassMetaData cmd =
2568                    modelMetaData.getClassMetaDataForObjectIdClass(
2569                            param.getClass());
2570            if (cmd != null) { // app identity objectid-class parameter
2571
OID oid = cmd.createOID(false);
2572                oid.fillFromPK(param);
2573                param = oid;
2574            }
2575        }
2576        return param;
2577    }
2578
2579
2580//==========================XAResource impl==================================
2581

2582
2583
2584    private int txTimeout = 3000;
2585    private Xid JavaDoc xid = null;
2586
2587
2588    private int txState;
2589    public static final int TX_INACTIVE = 0;
2590    public static final int TX_STARTED = 1;
2591    public static final int TX_FAIL = 2;
2592    public static final int TX_PREPARED = 4;
2593    public static final int TX_SUSPENDED = 8;
2594
2595    /**
2596     * If the pm is managed by a TransactionManager.
2597     */

2598    private boolean managed;
2599    /**
2600     * This is a flag to indicate if it was closed by the client in a managed env.
2601     */

2602    private boolean managedClosed = false;
2603
2604    /**
2605     * Is this pm managed by a container.
2606     *
2607     * @return
2608     */

2609    public boolean isManaged() {
2610        return managed;
2611    }
2612
2613    /**
2614     * set the state of the pm to be in a container.
2615     *
2616     * @param managed
2617     */

2618    public void setManaged(boolean managed) {
2619        this.managed = managed;
2620        this.managedClosed = false;
2621    }
2622
2623    /**
2624     * Called to associate the resource with a transaction.
2625     * <p/>
2626     * If the flags argument is {@link #TMNOFLAGS}, the transaction must not
2627     * previously have been seen by this resource manager, or an
2628     * {@link javax.transaction.xa.XAException} with error code XAER_DUPID will be thrown.
2629     * <p/>
2630     * If the flags argument is {@link #TMJOIN}, the resource will join a
2631     * transaction previously seen by its resource manager.
2632     * <p/>
2633     * If the flags argument is {@link #TMRESUME} the resource will
2634     * resume the transaction association that was suspended with
2635     * end(TMSUSPEND).
2636     *
2637     * @param xid The id of the transaction to associate with.
2638     * @param flags Must be either {@link #TMNOFLAGS}, {@link #TMJOIN}
2639     * or {@link #TMRESUME}.
2640     * @throws javax.transaction.xa.XAException
2641     * If an error occurred.
2642     */

2643
2644    public void start(Xid JavaDoc xid, int flags) throws XAException JavaDoc {
2645        if (Debug.DEBUG) {
2646            Debug.OUT.println("***** JdoGeniePersistenceManagerImp.start ***** flag = "
2647                    + getFlagString(flags) + " for \n" + this);
2648            System.out.println("xid = " + xid);
2649        }
2650        checkInPool();
2651        switch (flags) {
2652            case TMNOFLAGS:
2653            case TMJOIN:
2654                begin(xid);
2655                break;
2656            case TMRESUME:
2657                if (checkId(xid)) {
2658                    resume(xid);
2659                }
2660                break;
2661            default:
2662                throw new XAException JavaDoc(
2663                        "Unsupported state for method start state = " + flags);
2664        }
2665    }
2666
2667
2668
2669    private boolean checkId(Xid JavaDoc xid) {
2670        if (!this.xid.equals(xid)) {
2671// throw new JDOFatalInternalException("The check id failed");
2672
return false;
2673        }
2674        return true;
2675    }
2676
2677
2678
2679    private void resume(Xid JavaDoc xid) throws XAException JavaDoc {
2680        checkInPool();
2681        if (this.txState != TX_SUSPENDED) {
2682            throw new XAException JavaDoc(
2683                    "Could resume a transaction that was not suspended");
2684        }
2685        this.txState = TX_STARTED;
2686    }
2687
2688
2689
2690    private void begin(Xid JavaDoc xid) throws XAException JavaDoc {
2691        checkInPool();
2692        if (this.txState == TX_INACTIVE) {
2693            this.xid = xid;
2694            try {
2695                beginImp();
2696                this.txState = TX_STARTED;
2697            } catch (Exception JavaDoc e) {
2698                throw new XAException JavaDoc(
2699                        "Could not begin a transaction : " + e.getMessage());
2700            }
2701        } else if (this.txState == TX_STARTED
2702                || this.txState == TX_PREPARED
2703                || this.txState == TX_SUSPENDED) {
2704            // Transaction on this pm has started already. Since beans will
2705
// share this pm, there will be multple calls to begin.
2706
return;
2707        } else {
2708            throw new XAException JavaDoc(
2709                    "Could not begin a transaction in state = " + txState);
2710        }
2711    }
2712
2713
2714    /**
2715     * Prepare to commit the work done on this resource in the given
2716     * transaction.
2717     * <p/>
2718     * This method cannot return a status indicating that the transaction
2719     * should be rolled back. If the resource wants the transaction to
2720     * be rolled back, it should throw an <code>XAException</code> at the
2721     * caller.
2722     *
2723     * @param xid The id of the transaction to prepare to commit work for.
2724     * @return Either {@link #XA_OK} or {@link #XA_RDONLY}.
2725     * @throws javax.transaction.xa.XAException
2726     * If an error occurred.
2727     */

2728
2729    public int prepare(Xid JavaDoc xid) throws XAException JavaDoc {
2730        if (Debug.DEBUG) {
2731            Debug.OUT.println(
2732                    "***** JdoGeniePersistenceManagerImp.prepare *****");
2733        }
2734        checkInPool();
2735        if (checkId(xid)) {
2736            if (txState == TX_STARTED) {
2737                try {
2738                    internalCommit(true);
2739                    this.txState = TX_PREPARED;
2740                    return XA_OK;
2741                } catch (Exception JavaDoc ex) {
2742                    ex.printStackTrace();
2743                    throw new XAException JavaDoc(
2744                            "Could not prepare commit : " + ex.getMessage());
2745                }
2746            } else if (this.txState == TX_PREPARED || this.txState == TX_SUSPENDED) {
2747                return XA_OK;
2748            } else {
2749                throw new XAException JavaDoc(
2750                        "Wrong state to commit phase one on : state = " + this.txState);
2751            }
2752        }
2753        return XA_OK;
2754    }
2755
2756
2757    /**
2758     * Commit the work done on this resource in the given transaction.
2759     * <p/>
2760     * If the <code>onePhase</code> argument is true, one-phase
2761     * optimization is being used, and the {@link #prepare(Xid) prepare}
2762     * method must not have been called for this transaction.
2763     * Otherwise, this is the second phase of the two-phase commit protocol.
2764     *
2765     * @param xid The id of the transaction to commit work for.
2766     * @param onePhase If true, the transaction manager is using one-phase
2767     * optimization.
2768     * @throws javax.transaction.xa.XAException
2769     * If an error occurred.
2770     */

2771
2772    public void commit(Xid JavaDoc xid, boolean onePhase) throws XAException JavaDoc {
2773        if (Debug.DEBUG) {
2774            Debug.OUT.println("***** JdoGeniePersistenceManagerImp.commit ***** onePhase: " + onePhase
2775                    + " for \n" + this);
2776        }
2777        checkInPool();
2778        if (checkId(xid)) {
2779            try {
2780                if (onePhase && txState == TX_STARTED) {
2781                    internalCommit(false);
2782                } else if (this.txState == TX_PREPARED) {
2783                    phaseCommit2();
2784                } else if (this.txState == TX_INACTIVE) {
2785                    return;
2786                } else {
2787                    throw new XAException JavaDoc("Unable to commit unexpected state: state = " +
2788                            txState + " for xid = " + xid);
2789                }
2790
2791                this.txState = TX_INACTIVE;
2792                this.xid = null;
2793            } catch (XAException JavaDoc ex) {
2794                ex.printStackTrace();
2795                throw ex;
2796            } catch (Exception JavaDoc ex) {
2797                ex.printStackTrace();
2798                throw new XAException JavaDoc("Could not commit : " + ex.getMessage());
2799            }
2800        }
2801    }
2802
2803
2804    private void checkInPool() {
2805        if (inPool) {
2806            throw BindingSupportImpl.getInstance().fatal(
2807                    "The pm is in the pool");
2808        }
2809    }
2810
2811    public boolean isInTx() {
2812        return this.txState != TX_INACTIVE;
2813    }
2814
2815    /**
2816     * Roll back the work done on this resource in the given transaction.
2817     *
2818     * @param xid The id of the transaction to rollback for.
2819     * @throws javax.transaction.xa.XAException
2820     * If an error occurred.
2821     */

2822
2823    public void rollback(Xid JavaDoc xid) throws XAException JavaDoc {
2824        if (Debug.DEBUG) {
2825            Debug.OUT.println(
2826                    "***** JdoGeniePersistenceManagerImp.rollback *****");
2827        }
2828        checkInPool();
2829        if (checkId(xid)) {
2830            try {
2831                if (this.txState != TX_INACTIVE) {
2832                    rollbackImp();
2833                    this.txState = TX_INACTIVE;
2834                }
2835                this.xid = null;
2836            } catch (Exception JavaDoc e) {
2837                throw new XAException JavaDoc("Could not rollback: " + e.getMessage());
2838            }
2839        }
2840    }
2841
2842
2843    /**
2844     * Called to disassociate the resource from a transaction.
2845     * <p/>
2846     * If the flags argument is {@link #TMSUCCESS}, the portion of work
2847     * was done sucessfully.
2848     * <p/>
2849     * If the flags argument is {@link #TMFAIL}, the portion of work
2850     * failed. The resource manager may mark the transaction for
2851     * rollback only to avoid the transaction being committed.
2852     * <p/>
2853     * If the flags argument is {@link #TMSUSPEND} the resource will
2854     * temporarily suspend the transaction association. The transaction
2855     * must later be re-associated by giving the {@link #TMRESUME} state
2856     * to the {@link #start(Xid,int) start} method.
2857     *
2858     * @param xid The id of the transaction to disassociate from.
2859     * @param flags Must be either {@link #TMSUCCESS}, {@link #TMFAIL}
2860     * or {@link #TMSUSPEND}.
2861     * @throws javax.transaction.xa.XAException
2862     * If an error occurred.
2863     */

2864
2865    public void end(Xid JavaDoc xid, int flags) throws XAException JavaDoc {
2866        if (Debug.DEBUG) {
2867            Debug.OUT.println("***** JdoGeniePersistenceManagerImp.end ***** flag: " + getFlagString(
2868                    flags)
2869                    + " for \n" + this);
2870            System.out.println("xid = " + xid);
2871        }
2872        checkInPool();
2873        if (checkId(xid)) {
2874            switch (flags) {
2875                case TMSUCCESS:
2876                    this.txState = TX_STARTED;
2877                    break;
2878                case TMFAIL:
2879                    this.txState = TX_FAIL;
2880                    break;
2881                case TMSUSPEND:
2882                    this.txState = TX_SUSPENDED;
2883                    break;
2884                default:
2885                    throw new XAException JavaDoc(
2886                            "Unable to end transaction = " + xid + " unhandled flag = " + flags);
2887            }
2888        }
2889    }
2890
2891
2892    private String JavaDoc getFlagString(int flag) {
2893        switch (flag) {
2894            case 8388608:
2895                return "TMENDRSCAN";
2896            case 536870912:
2897                return "TMFAIL";
2898            case 2097152:
2899                return "TMJOIN";
2900            case 0:
2901                return "TMNOFLAGS";
2902            case 1073741824:
2903                return "TMONEPHASE";
2904            case 134217728:
2905                return "TMRESUME";
2906            case 16777216:
2907                return "TMSTARTRSCAN";
2908            case 67108864:
2909                return "TMSUCCESS";
2910            case 33554432:
2911                return "TMSUSPEND";
2912            default:
2913                return "UNKNOWN";
2914        }
2915    }
2916
2917    /**
2918     * Tells the resource manager to forget about a heuristic decision.
2919     *
2920     * @param xid The id of the transaction that was ended with a heuristic
2921     * decision.
2922     * @throws javax.transaction.xa.XAException
2923     * If an error occurred.
2924     */

2925
2926    public void forget(Xid JavaDoc xid) throws XAException JavaDoc {
2927        if (Debug.DEBUG) {
2928            Debug.OUT.println(
2929                    "***** JdoGeniePersistenceManagerImp.forget *****");
2930        }
2931        checkInPool();
2932        if (this.xid.equals(xid)) {
2933            this.txState = TX_STARTED;
2934        }
2935    }
2936
2937
2938    /**
2939     * Get the current transaction timeout value for this resource.
2940     *
2941     * @return The current timeout value, in seconds.
2942     * @throws javax.transaction.xa.XAException
2943     * If an error occurred.
2944     */

2945
2946    public int getTransactionTimeout() throws XAException JavaDoc {
2947        if (Debug.DEBUG) {
2948            Debug.OUT.println(
2949                    "***** JdoGeniePersistenceManagerImp.getTransactionTimeout *****");
2950        }
2951        checkInPool();
2952        return txTimeout;
2953    }
2954
2955
2956    /**
2957     * This method does not check for inPool because Weblogic seems to keep
2958     * a ref around of used ones to try and re-use it. This happens even though
2959     * it was delisted from transaction.
2960     * <p/>
2961     * Tells the caller if this resource has the same resource manager
2962     * as the argument resource.
2963     * <p/>
2964     * The transaction manager needs this method to be able to decide
2965     * if the {@link #start(Xid,int) start} method should be given the
2966     * {@link #TMJOIN} state.
2967     *
2968     * @throws javax.transaction.xa.XAException
2969     * If an error occurred.
2970     */

2971
2972    public boolean isSameRM(XAResource JavaDoc xaResource) throws XAException JavaDoc {
2973        if (Debug.DEBUG) {
2974            Debug.OUT.println(
2975                    "***** JdoGeniePersistenceManagerImp.isSameRM *****");
2976            Debug.OUT.println("***** isSame: this = " + this);
2977            Debug.OUT.println("***** isSame: other = " + this);
2978        }
2979        return xaResource == this;
2980    }
2981
2982
2983    /**
2984     * Return a list of transactions that are in a prepared or heuristically
2985     * state.
2986     * <p/>
2987     * This method looks not only at the resource it is invoked on, but
2988     * also on all other resources managed by the same resource manager.
2989     * It is intended to be used by the application server when recovering
2990     * after a server crash.
2991     * <p/>
2992     * A recovery scan is done with one or more calls to this method.
2993     * At the first call, {@link #TMSTARTRSCAN} must be in the
2994     * <code>state</code> argument to indicate that the scan should be started.
2995     * During the recovery scan, the resource manager maintains an internal
2996     * cursor that keeps track of the progress of the recovery scan.
2997     * To end the recovery scan, the {@link #TMENDRSCAN} must be passed
2998     * in the <code>state</code> argument.
2999     *
3000     * @param flag Must be either {@link #TMNOFLAGS}, {@link #TMSTARTRSCAN},
3001     * {@link #TMENDRSCAN} or <code>TMSTARTRSCAN|TMENDRSCAN</code>.
3002     * @return An array of zero or more transaction ids.
3003     * @throws javax.transaction.xa.XAException
3004     * If an error occurred.
3005     */

3006
3007    public Xid JavaDoc[] recover(int flag) throws XAException JavaDoc {
3008        if (Debug.DEBUG) {
3009            Debug.OUT.println("***** JdoGeniePersistenceManagerImp.recover ***** flag = " + getFlagString(
3010                    flag));
3011        }
3012        checkInPool();
3013        Xid JavaDoc[] xids = txState == TX_PREPARED ? new Xid JavaDoc[]{xid} : null;
3014        return xids;
3015    }
3016
3017
3018    /**
3019     * Set the transaction timeout value for this resource.
3020     * <p/>
3021     * If the <code>seconds</code> argument is <code>0</code>, the
3022     * timeout value is set to the default timeout value of the resource
3023     * manager.
3024     * <p/>
3025     * Not all resource managers support setting the timeout value.
3026     * If the resource manager does not support setting the timeout
3027     * value, it should return false.
3028     *
3029     * @param seconds The timeout value, in seconds.
3030     * @return True if the timeout value could be set, otherwise false.
3031     * @throws javax.transaction.xa.XAException
3032     * If an error occurred.
3033     */

3034
3035    public boolean setTransactionTimeout(int seconds) throws XAException JavaDoc {
3036        if (Debug.DEBUG) {
3037            Debug.OUT.println(
3038                    "***** JdoGeniePersistenceManagerImp.setTransactionTimeout *****");
3039        }
3040        checkInPool();
3041        if (seconds < -1) {
3042            return false;
3043        } else {
3044            this.txTimeout = seconds;
3045        }
3046        return true;
3047    }
3048
3049
3050
3051//====================Synchronization imp==============================
3052

3053
3054
3055    public void afterCompletion(int status) {
3056        if (Debug.DEBUG) {
3057            Debug.OUT.println(
3058                    "***** JdoGeniePersistenceManagerImp.afterCompletion *****");
3059        }
3060        proxy.resetPM();
3061        pmf.pmClosedNotification(this, false, false);
3062    }
3063
3064
3065
3066    public void beforeCompletion() {
3067        if (Debug.DEBUG) {
3068            Debug.OUT.println(
3069                    "***** JdoGeniePersistenceManagerImp.beforeCompletion *****");
3070        }
3071    }
3072
3073
3074    /**
3075     * Set the locking mode for datastore transactions. This method may only
3076     * be called when no transaction is active. You can set the default value
3077     * for this property using the Workbench or edit your .jdogenie file
3078     * directly (datastore.tx.locking property).
3079     *
3080     * @see #LOCKING_NONE
3081     * @see #LOCKING_FIRST
3082     * @see #LOCKING_ALL
3083     */

3084    public void setDatastoreTxLocking(int mode) {
3085        int policy;
3086        switch (mode) {
3087            case VersantPersistenceManager.LOCKING_NONE:
3088                policy = StorageManager.LOCK_POLICY_NONE;
3089                break;
3090            case VersantPersistenceManager.LOCKING_FIRST:
3091                policy = StorageManager.LOCK_POLICY_FIRST;
3092                break;
3093            case VersantPersistenceManager.LOCKING_ALL:
3094                policy = StorageManager.LOCK_POLICY_ALL;
3095                break;
3096            default:
3097                throw BindingSupportImpl.getInstance().invalidOperation(
3098                        "Invalid datastoreTxLocking mode: " + mode);
3099        }
3100        sm.setLockingPolicy(policy);
3101    }
3102
3103    /**
3104     * Get the locking mode for datastore transactions.
3105     */

3106    public int getDatastoreTxLocking() {
3107        switch (sm.getLockingPolicy()) {
3108            case StorageManager.LOCK_POLICY_NONE:
3109                return VersantPersistenceManager.LOCKING_NONE;
3110            case StorageManager.LOCK_POLICY_FIRST:
3111                return VersantPersistenceManager.LOCKING_FIRST;
3112            case StorageManager.LOCK_POLICY_ALL:
3113                return VersantPersistenceManager.LOCKING_ALL;
3114        }
3115        return VersantPersistenceManager.LOCKING_NONE;
3116    }
3117
3118    public void logEvent(int level, String JavaDoc description, int ms) {
3119        sm.logEvent(level, description, ms);
3120    }
3121
3122    /**
3123     * Return the instance for oid if it is present in the local PM cache
3124     * otherwise return null. Note that the instances might still be hollow
3125     * and touching its fields will cause a fetch from the level 2 cache
3126     * or database.
3127     *
3128     * @see #isHollow(Object)
3129     */

3130    public Object JavaDoc getObjectByIdFromCache(Object JavaDoc oid) {
3131        if (oid == null) {
3132            throw BindingSupportImpl.getInstance().invalidOperation(
3133                    "The oid is null");
3134        }
3135        try {
3136            PCStateMan stateMan = cache.getByOID(extractOID(oid),
3137                    true);
3138            return stateMan == null ? null : stateMan.pc;
3139        } catch (Exception JavaDoc e) {
3140            handleException(e);
3141            return null;
3142        }
3143    }
3144
3145    /**
3146     * Is the instance hollow? Hollow instances are managed but their fields
3147     * have not been loaded from the level 2 cache or database.
3148     *
3149     * @see #getObjectByIdFromCache(Object)
3150     */

3151    public boolean isHollow(Object JavaDoc pc) {
3152        PCStateMan pcStateObject = pmPreCheck(pc);
3153        return pcStateObject != null && pcStateObject.isHollow();
3154    }
3155
3156    /**
3157     * Does the instance have an identity? New instances are only assigned
3158     * an identity on commit or flush or when the application executes an
3159     * operation that requires the identity.
3160     */

3161    public boolean hasIdentity(Object JavaDoc pc) {
3162        return !pmPreCheck(pc).oid.isNew();
3163    }
3164
3165    /**
3166     * Process the ReferenceQueue for the local cache. This is called when
3167     * a query fetches data from the server to ensure that long running
3168     * read-only transactions do not leak SoftReferences.
3169     */

3170    public void processLocalCacheReferenceQueue() {
3171        cache.processReferenceQueue();
3172    }
3173
3174    /**
3175     * This method makes detached copies of the parameter instances and returns
3176     * the copies as the result of the method. The order of instances in the
3177     * parameter Collection's iteration corresponds to the order of corresponding
3178     * instances in the returned Collection's iteration.
3179     * <p/>
3180     * The Collection of instances is first made persistent, and the reachability
3181     * algorithm is run on the instances. This ensures that the closure of all
3182     * of the instances in the the parameter Collection is persistent.
3183     * <p/>
3184     * For each instance in the parameter Collection, a corresponding detached
3185     * copy is created. Each field in the persistent instance is handled based on
3186     * its type and whether the field is contained in the fetch group for the
3187     * persistence-capable class. If there are duplicates in the parameter
3188     * Collection, the corresponding detached copy is used for each such duplicate.
3189     */

3190    public Collection versantDetachCopy(Collection pcs, String JavaDoc fetchGroup) {
3191        if (pcs instanceof QueryResult) {
3192            //this is done to resolve the queryresult to avoid extra queries
3193
// when iterating over it
3194
pcs.size();
3195        }
3196
3197        if (fetchGroup == null) fetchGroup = FetchGroup.DFG_NAME;
3198        for (Iterator pcIt = pcs.iterator(); pcIt.hasNext();) {
3199            Object JavaDoc o = pcIt.next();
3200            if (o == null || !(o instanceof VersantDetachable)) continue;
3201            VersantDetachable pc = (VersantDetachable)o;
3202            requestedPCState = null;
3203            pc.jdoGetPersistenceManager();
3204            if (requestedPCState == null) {
3205                makePersistent(pc);
3206            }
3207        }
3208        flushRetainState();
3209        // load the container with the initial root collection
3210
DetachStateContainer dsc = new DetachStateContainer(this);
3211        for (Iterator pcIt = pcs.iterator(); pcIt.hasNext();) {
3212            PersistenceCapable pc = (PersistenceCapable)pcIt.next();
3213            if (pc == null) continue;
3214            PCStateMan sm = getInternalSM(pc);
3215            ClassMetaData cmd = sm.state.getClassMetaData(modelMetaData);
3216            FetchGroup fg = cmd.getFetchGroup(fetchGroup);
3217            if (fg == null) {
3218                fg = cmd.fetchGroups[0];
3219            }
3220            dsc.add(sm.oid, sm.state, fg);
3221        }
3222
3223        // find all states reachable via the fetch group
3224
for (; dsc.hasNextFetchGroup();) {
3225            State state = dsc.getNextFetchGroupState();
3226            FetchGroup fg = dsc.getNextFetchGroup();
3227            OID oid = dsc.getNextFetchGroupOID();
3228
3229            // if we have to load the fetch group then there is no need to check
3230
// any of its fields - all of the States referenced by the fetch
3231
// group will have been added to the StatesReturned on the
3232
// server and will be added to our dcs
3233
if (!oid.isNew() && (state == null || !state.containsFetchGroup(fg))) {
3234                StatesReturned con = getStateForDetach(oid, fg.index);
3235                addToDetachStateContainer(con, dsc);
3236                state = con.get(oid);
3237                addToCache(con);
3238                dsc.add(oid, state, fg);
3239            }
3240            ClassMetaData cmd = state.getClassMetaData(modelMetaData);
3241            state.addFetchGroupStatesToDCS(fg, dsc, this, oid, cmd);
3242        }
3243        dsc.createPcClasses(modelMetaData);
3244        ArrayList copyList = new ArrayList(pcs.size());
3245        for (Iterator pcIt = pcs.iterator(); pcIt.hasNext();) {
3246            Object JavaDoc o = pcIt.next();
3247            if (o == null || !(o instanceof VersantDetachable)) {
3248                copyList.add(null);
3249                continue;
3250            }
3251            VersantDetachable pc = (VersantDetachable)o;
3252            requestedPCState = null;
3253            pc.jdoGetPersistenceManager();
3254            if (requestedPCState == null) {
3255                copyList.add(pc);
3256            }
3257            copyList.add(dsc.getDetachCopy(pc));
3258        }
3259        return copyList;
3260    }
3261
3262    public List versantCollectReachable(Collection roots, String JavaDoc fetchGroup) {
3263        if (fetchGroup == null) {
3264            fetchGroup = FetchGroup.REF_NAME;
3265        }
3266        checkActiveTx();
3267
3268        Set result = new HashSet();
3269        List todo = new ArrayList(roots);
3270
3271        while (todo.size() > 0) // non-recursive!
3272
{
3273            Object JavaDoc o = todo.remove(0);
3274            String JavaDoc currentFetchGroup = fetchGroup;
3275            if (o instanceof Object JavaDoc[]) { // added by sm.collectReachable
3276
Object JavaDoc[] tmp = (Object JavaDoc[])o;
3277                currentFetchGroup = (String JavaDoc)tmp[1];
3278                o = tmp[0];
3279            }
3280
3281            if (o == null || !(o instanceof PersistenceCapable)) continue;
3282            PersistenceCapable pc = (PersistenceCapable)o;
3283
3284            requestedPCState = null;
3285            pc.jdoGetPersistenceManager();
3286            if (requestedPCState == null) {
3287                makePersistent(pc);
3288            }
3289            PCStateMan sm = pmPreCheck(pc);
3290            if (!result.contains(sm) && !sm.isDeleted(pc)) {
3291                if (currentFetchGroup != null)
3292                // nextFetchGroup was defined for the referencing field
3293
{
3294                    sm.collectReachable(currentFetchGroup, todo);
3295                }
3296                result.add(sm);
3297            }
3298        }
3299        List pcresult = new ArrayList();
3300        for (Iterator it = result.iterator(); it.hasNext();) {
3301            pcresult.add(((PCStateMan)it.next()).pc);
3302        }
3303        return pcresult;
3304    }
3305
3306    /**
3307     * This is called by sm's if they require a field.
3308     * This will update the managedCache with the requested data.
3309     */

3310    public StatesReturned getStateForDetach(OID oid, int fgi) {
3311        return getStateJdoConnection(oid, null, fgi,
3312                oid.getAvailableClassId(), false,
3313                -1, -1);
3314    }
3315
3316    public State getStateFromLocalCacheById(Object JavaDoc oid) {
3317        if (oid == null) {
3318            throw BindingSupportImpl.getInstance().invalidOperation(
3319                    "The supplied oid is null");
3320        }
3321        try {
3322            OID nOID = extractOID(oid);
3323            PCStateMan stateMan = cache.getByOID(nOID, true);
3324            if (stateMan == null) {
3325                return null;
3326            }
3327            return stateMan.state;
3328        } catch (Exception JavaDoc e) {
3329            handleException(e);
3330            return null;
3331        }
3332    }
3333
3334    /**
3335     * This util method is used by collection types to preload their pc
3336     * entries. It tests to determine if the states refered to by the oids is
3337     * in the managed cache. If not they must be bulk loaded from server.
3338     * The scenario in which this is likely to happen is when the collection
3339     * is not in the default fetch group and the state is in cache with the
3340     * collection filled in. If this collection field is read then the
3341     * pcstateman will determine that the stateField is filled and hence not
3342     * ask the server for it.
3343     */

3344    public int getObjectsById(Object JavaDoc[] oids, int length, Object JavaDoc[] data,
3345            int stateFieldNo, int classMetaDataIndex) {
3346        if (oids == null || oids.length <= 0) return 0;
3347        OIDArray oidArray = new OIDArray();
3348        for (int i = 0; i < length; i++) {
3349            Object JavaDoc o = oids[i];
3350// if (o == null) {
3351
// length = i;
3352
// break;
3353
// }
3354
if (!(o instanceof OID)) {
3355                data[i] = o;
3356                continue;
3357            }
3358            OID oid = (OID)o;
3359            PCStateMan pcStateMan = cache.getByOID(oid, true);
3360            if (pcStateMan != null) {
3361                data[i] = pcStateMan.pc;
3362            } else {
3363                oidArray.add(oid);
3364                data[i] = null;
3365            }
3366        }
3367        if (!oidArray.isEmpty()) {
3368            FieldMetaData triggerField;
3369            if (classMetaDataIndex >= 0) { // navigated stateFieldNo
3370
ClassMetaData navCmd = modelMetaData.classes[classMetaDataIndex];
3371                triggerField = navCmd.stateFields[stateFieldNo];
3372            } else {
3373                triggerField = null;
3374            }
3375            StatesReturned container = sm.fetch(this, oidArray, triggerField);
3376            // keep a reference to each of the returned PCStateMan's so
3377
// that they are not GCed before we reference them
3378
PCStateMan[] nogc = addToCacheAndManage(container);
3379            for (int i = 0; i < length; i++) {
3380                if (data[i] == null) {
3381                    data[i] = cache.getByOID((OID)oids[i], true).pc;
3382                }
3383            }
3384            if (nogc == null) {
3385                // dummy code to keep IDE happy and to hopefully prevent
3386
// any overzealous optimization from removing nogc
3387
}
3388        }
3389        return length;
3390    }
3391
3392    /**
3393     * Construct a new query instance with the given candidate class from a
3394     * named query. The query name given must be the name of a query defined
3395     * in metadata. The metadata is searched for the specified name.
3396     * This is a JDO 2 preview feature.
3397     */

3398    public Query versantNewNamedQuery(Class JavaDoc cls, String JavaDoc queryName) {
3399        try {
3400            ClassMetaData cmd = modelMetaData.getClassMetaData(cls);
3401            if (cmd == null) {
3402                throw BindingSupportImpl.getInstance().invalidOperation("Class " + cls.getName() +
3403                        " is not persistent");
3404            }
3405            QueryDetails qp = cmd.getNamedQuery(queryName);
3406            if (qp == null) {
3407                throw BindingSupportImpl.getInstance().invalidOperation("No query called '" + queryName +
3408                        "' has been defined in the meta data for Class " +
3409                        cmd.qname);
3410            }
3411            return new VersantQueryImp(proxy, qp);
3412        } catch (Exception JavaDoc e) {
3413            handleException(e);
3414            return null;
3415        }
3416    }
3417
3418    /**
3419     * Must bidirectional relationships be checked for consistency
3420     * on commit or flush?
3421     */

3422    public boolean isCheckModelConsistencyOnCommit() {
3423        return checkModelConsistencyOnCommit;
3424    }
3425
3426    public void setCheckModelConsistencyOnCommit(boolean on) {
3427        this.checkModelConsistencyOnCommit = on;
3428    }
3429
3430    /**
3431     * This method applies the changes contained in the collection of detached
3432     * instances to the corresponding persistent instances in the cache and
3433     * returns a collection of persistent instances that exactly corresponds to
3434     * the parameter instances. The order of instances in the parameter
3435     * Collection's iteration corresponds to the order of corresponding
3436     * instances in the returned Collection's iteration.
3437     * <p/>
3438     * Changes made to instances while detached are applied to the corresponding
3439     * persistent instances in the cache. New instances associated with the
3440     * detached instances are added to the persistent instances in the
3441     * corresponding place.
3442     */

3443    public Collection versantAttachCopy(Collection detached,
3444            boolean makeTransactional) {
3445        return versantAttachCopy(detached, makeTransactional, false);
3446    }
3447
3448    /**
3449     * This method applies the changes contained in the collection of detached
3450     * instances to the corresponding persistent instances in the cache and
3451     * returns a collection of persistent instances that exactly corresponds to
3452     * the parameter instances. The order of instances in the parameter
3453     * Collection's iteration corresponds to the order of corresponding
3454     * instances in the returned Collection's iteration.
3455     * <p/>
3456     * Changes made to instances while detached are applied to the corresponding
3457     * persistent instances in the cache. New instances associated with the
3458     * detached instances are added to the persistent instances in the
3459     * corresponding place.
3460     *
3461     * @param detached VersantDetachable objects to attach in the current
3462     * transaction
3463     * @param shallow attach only the objects in 'detached' Collection and not
3464     * reachable objects if true.
3465     */

3466    public Collection versantAttachCopy(Collection detached,
3467            boolean makeTransactional, boolean shallow) {
3468        AttachStateContainer asc = new AttachStateContainer(this);
3469        for (Iterator pcIt = detached.iterator(); pcIt.hasNext();) {
3470            VersantDetachable detachable = (VersantDetachable)pcIt.next();
3471            if (detachable == null) continue;
3472            asc.addVersantDetachable(detachable);
3473        }
3474        if (!shallow) {
3475            AttachNavStateManager ansm = new AttachNavStateManager(asc);
3476            for (int c = 0; c < asc.getDetachedSize(); c++) {
3477                VersantDetachable detachable = asc.getVersantDetachable(c);
3478                if (detachable.jdoGetPersistenceManager() != null) continue;
3479                detachable.jdoReplaceStateManager(ansm);
3480                ClassMetaData cmd = modelMetaData.getClassMetaData(
3481                        detachable.getClass());
3482                for (; cmd != null; cmd = cmd.pcSuperMetaData) {
3483                    for (int i = 0; i < cmd.fields.length; i++) {
3484                        FieldMetaData field = cmd.fields[i];
3485                        if (field.fake) continue;
3486                        switch (field.category) {
3487                            case FieldMetaData.CATEGORY_REF:
3488                            case FieldMetaData.CATEGORY_POLYREF:
3489                            case FieldMetaData.CATEGORY_COLLECTION:
3490                            case FieldMetaData.CATEGORY_MAP:
3491                            case FieldMetaData.CATEGORY_ARRAY:
3492                                detachable.jdoProvideField(
3493                                        field.managedFieldNo);
3494                        }
3495                    }
3496                }
3497            }
3498        }
3499
3500        AttachCopyStateManager acsm = new AttachCopyStateManager(this);
3501        for (int c = 0; c < asc.getDetachedSize(); c++) {
3502            OID oid = asc.getOID(c);
3503            VersantDetachable detachable = asc.getVersantDetachable(c);
3504            if (detachable.jdoGetPersistenceManager() != null) continue;
3505            boolean notNew = !oid.isNew();
3506            if (notNew && !detachable.versantIsDirty()) continue;
3507            detachable.jdoReplaceStateManager(acsm);
3508            PCStateMan sm = getInternalSM(oid);
3509            if (notNew && sm.state.isHollow()) {
3510                StatesReturned con = getStateForDetach(oid, 0);
3511                addToCache(con);
3512            }
3513            acsm.setState(sm.state);
3514            if (notNew) {
3515                Object JavaDoc dVersion = detachable.versantGetVersion();
3516                Object JavaDoc aVersion = sm.getOptimisticLockingValue();
3517                if (aVersion == null && sm.getClassMetaData().optimisticLockingField != null) {
3518                    throw BindingSupportImpl.getInstance().internal("Optimistic locking value not available for "
3519                            + sm.getClassMetaData().qname);
3520                }
3521                if (aVersion != null && !aVersion.equals(dVersion)) {
3522                    throw BindingSupportImpl.getInstance().concurrentUpdate(
3523                            "The object (" + oid.toStringImp() +
3524                            ") has been updated since its been detached " +
3525                            "(current='" + aVersion + "', detached='" + dVersion + "')", oid);
3526                }
3527            }
3528            ClassMetaData cmd = modelMetaData.getClassMetaData(
3529                    detachable.getClass());
3530            for (; cmd != null; cmd = cmd.pcSuperMetaData) {
3531                for (int i = 0; i < cmd.fields.length; i++) {
3532                    FieldMetaData fmd = cmd.fields[i];
3533                    if (fmd.fake) continue;
3534                    if (notNew && !detachable.versantIsDirty(
3535                            fmd.getManagedFieldNo())) {
3536                        continue;
3537                    }
3538                    switch (fmd.category) {
3539                        case FieldMetaData.CATEGORY_SIMPLE:
3540                        case FieldMetaData.CATEGORY_POLYREF:
3541                        case FieldMetaData.CATEGORY_EXTERNALIZED:
3542                        case FieldMetaData.CATEGORY_REF:
3543                        case FieldMetaData.CATEGORY_COLLECTION:
3544                        case FieldMetaData.CATEGORY_ARRAY:
3545                        case FieldMetaData.CATEGORY_MAP:
3546                            acsm.setFieldMetaData(fmd);
3547                            int managedFieldNo = fmd.managedFieldNo;
3548                            detachable.jdoProvideField(managedFieldNo);
3549                            if (notNew) {
3550                                sm.makeDirty(detachable, managedFieldNo);
3551                            }
3552                    }
3553                }
3554            }
3555            if (notNew) {
3556                sm.resetLoadedFields();
3557                sm.setLoadRequired();
3558            }
3559        }
3560        Collection deleted = asc.getDeleted();
3561        for (Iterator it = deleted.iterator(); it.hasNext();) {
3562            try {
3563                Object JavaDoc o = getObjectById(it.next(), true);
3564                deletePersistent(o);
3565            } catch (JDOObjectNotFoundException e) {
3566                // Do Nothing
3567
}
3568        }
3569        ArrayList attached = new ArrayList();
3570        for (Iterator pcIt = detached.iterator(); pcIt.hasNext();) {
3571            VersantDetachable pc = (VersantDetachable)pcIt.next();
3572            if (pc == null) {
3573                attached.add(pc);
3574                continue;
3575            }
3576            Object JavaDoc newPC = getObjectById(getOID(pc), false);
3577            attached.add(newPC);
3578        }
3579        return attached;
3580    }
3581
3582    OID getOID(VersantDetachable detachable) {
3583        Object JavaDoc oid = detachable.versantGetOID();
3584        if (oid == null) {
3585            PersistenceManager pm = detachable.jdoGetPersistenceManager();
3586            if (pm != null) {
3587                if (pm instanceof PMProxy) {
3588                    pm = ((PMProxy)pm).getRealPM();
3589                }
3590                if (pm instanceof VersantPersistenceManagerImp) {
3591                    OID internalOID = ((VersantPersistenceManagerImp)pm).getInternalOID(
3592                            detachable);
3593                    detachable.versantSetOID(getExternalOID(internalOID));
3594                    return internalOID;
3595                } else {
3596                    throw BindingSupportImpl.getInstance().runtime(
3597                            "Can't attach a managed " +
3598                            "instance that is not managed by Versant Open Access");
3599                }
3600            }
3601            PCStateMan sm = getStateObject();
3602            NewObjectOID nOID = assignOID(detachable);
3603            sm.init(detachable, nOID, this);
3604            cache.add(sm);
3605            detachable.versantSetOID(nOID);
3606            return sm.oid.getAvailableOID();
3607        } else {
3608            return extractOID(oid);
3609        }
3610    }
3611
3612
3613    final PCStateMan getStateManager(Object JavaDoc o) {
3614        return cache.getByOID(
3615                extractOID(((PersistenceCapable)o).jdoGetObjectId()), false);
3616    }
3617
3618    final PCStateMan getStateManagerById(Object JavaDoc oid) {
3619        return cache.getByOID(extractOID(oid), false);
3620    }
3621
3622    public void setRetainConnectionInOptTx(boolean on) {
3623        sm.setConnectionPolicy(on
3624            ? StorageManager.CON_POLICY_PIN_FOR_TX
3625            : StorageManager.CON_POLICY_RELEASE);
3626    }
3627
3628    /**
3629     * Clear all epc fields.
3630     */

3631    private void resetEpcFields() {
3632        epcAll = false;
3633        epcObjects = null;
3634        epcObjectCount = 0;
3635        epcClasses = null;
3636        epcClassCount = 0;
3637        epcClassPresent = null;
3638    }
3639
3640    public void evictFromL2CacheAfterCommit(Object JavaDoc o) {
3641        checkActiveTx();
3642        evictFromL2CacheAfterCommitImp(o);
3643    }
3644
3645    /**
3646     * Version of {@link #evictFromL2CacheAfterCommit} without the active tx
3647     * check for interna use.
3648     */

3649    public void evictFromL2CacheAfterCommitImp(Object JavaDoc o) {
3650        if (epcAll) return;
3651        if (o instanceof PersistenceCapable) {
3652            PCStateMan sm = pmPreCheck((PersistenceCapable)o);
3653            if (sm == null || sm.isNew(null)) {
3654                return; // no need to evict transient or new objects
3655
}
3656            o = sm.oid;
3657        }
3658        if (epcObjects == null) {
3659            epcObjects = new Object JavaDoc[4];
3660        } else if (epcObjectCount == epcObjects.length) {
3661            Object JavaDoc[] a = new Object JavaDoc[epcObjects.length * 3 / 2 + 1];
3662            System.arraycopy(epcObjects, 0, a, 0, epcObjects.length);
3663            epcObjects = a;
3664        }
3665        epcObjects[epcObjectCount++] = o;
3666    }
3667
3668    public void evictAllFromL2CacheAfterCommit(final Object JavaDoc[] data) {
3669        checkActiveTx();
3670        int n = data.length;
3671        if (n == 0 || epcAll) return;
3672        ensureCapacityEpcObjects(n);
3673        for (int i = 0; i < n; i++) {
3674            Object JavaDoc o = data[i];
3675            if (o instanceof PersistenceCapable) {
3676                PCStateMan sm = pmPreCheck((PersistenceCapable)o);
3677                if (sm == null || sm.isNew(null)) {
3678                    continue; // no need to evict transient or new objects
3679
}
3680                o = sm.oid;
3681            }
3682            epcObjects[epcObjectCount++] = o;
3683        }
3684    }
3685
3686    public void evictAllFromL2CacheAfterCommit(final Collection data) {
3687        checkActiveTx();
3688        int n = data.size();
3689        if (n == 0 || epcAll) return;
3690        ensureCapacityEpcObjects(n);
3691        for (Iterator i = data.iterator(); i.hasNext();) {
3692            Object JavaDoc o = i.next();
3693            if (o instanceof PersistenceCapable) {
3694                PCStateMan sm = pmPreCheck((PersistenceCapable)o);
3695                if (sm == null || sm.isNew(null)) {
3696                    continue; // no need to evict transient or new objects
3697
}
3698                o = sm.oid;
3699            }
3700            epcObjects[epcObjectCount++] = o;
3701        }
3702    }
3703
3704    private void ensureCapacityEpcObjects(int delta) {
3705        if (epcObjects == null) {
3706            epcObjects = new Object JavaDoc[delta + 4];
3707        } else if (epcObjectCount + delta >= epcObjects.length) {
3708            Object JavaDoc[] a = new Object JavaDoc[epcObjectCount + delta];
3709            System.arraycopy(epcObjects, 0, a, 0, epcObjects.length);
3710            epcObjects = a;
3711        }
3712    }
3713
3714    public void evictAllFromL2CacheAfterCommit(final Class JavaDoc cls,
3715            final boolean includeSubclasses) {
3716        checkActiveTx();
3717        ClassMetaData cmd = modelMetaData.getClassMetaData(cls);
3718        if (cmd == null) {
3719            BindingSupportImpl.getInstance().runtime(
3720                    "Class is not persistent: " + cls);
3721        }
3722        evictAllFromL2CacheAfterCommitImp(cmd, includeSubclasses);
3723    }
3724
3725    private void evictAllFromL2CacheAfterCommitImp(ClassMetaData cmd,
3726            final boolean includeSubclasses) {
3727        if (epcAll) return;
3728        if (epcClasses == null) {
3729            epcClasses = new int[4];
3730            epcClassPresent = new boolean[modelMetaData.classes.length];
3731        }
3732        int ci = cmd.index;
3733        if (!epcClassPresent[ci]) {
3734            if (epcClassCount == epcClasses.length) {
3735                int[] a = new int[epcClasses.length * 2];
3736                System.arraycopy(epcClasses, 0, a, 0, epcClasses.length);
3737                epcClasses = a;
3738            }
3739            epcClasses[epcClassCount++] = ci;
3740            epcClassPresent[ci] = true;
3741        }
3742        if (includeSubclasses) {
3743            ClassMetaData[] subs = cmd.pcSubclasses;
3744            if (subs != null) {
3745                for (int i = subs.length - 1; i >= 0; i--) {
3746                    evictAllFromL2CacheAfterCommitImp(subs[i],
3747                            includeSubclasses);
3748                }
3749            }
3750        }
3751    }
3752
3753    public void evictAllFromL2CacheAfterCommit() {
3754        checkActiveTx();
3755        epcAll = true;
3756        epcObjects = null;
3757        epcObjectCount = 0;
3758        epcClasses = null;
3759        epcClassCount = 0;
3760        epcClassPresent = null;
3761    }
3762
3763    public Object JavaDoc getOptimisticLockingValue(Object JavaDoc o) {
3764        return getInternalSM((PersistenceCapable)o).getOptimisticLockingValue();
3765    }
3766
3767    public void setListeners(LifecycleListenerManager listeners) {
3768        this.listeners = listeners;
3769    }
3770
3771    public void addLifecycleListener(LifecycleListener listener,
3772            Class JavaDoc[] classes) {
3773        if (classes != null) {
3774            BindingSupportImpl.getInstance().runtime("Support for non-null " +
3775                    "classes parameter has not been implemented");
3776        }
3777        if (listeners == null) {
3778            listeners = new LifecycleListenerManager(listener);
3779        } else {
3780            listeners = listeners.add(listener);
3781        }
3782    }
3783
3784    public void removeLifecycleListener(LifecycleListener listener) {
3785        if (listeners == null) {
3786            return;
3787        }
3788        listeners = listeners.remove(listener);
3789    }
3790
3791    /**
3792     * Fire a delete to all of the LifecycleListener's for o.
3793     */

3794    public void fireDelete(ClassMetaData cmd, Object JavaDoc o) {
3795        if (listeners != null) {
3796            listeners.fireDelete(o);
3797        }
3798    }
3799
3800    /**
3801     * Get our StorageManager.
3802     */

3803    public StorageManager getStorageManager() {
3804        return sm;
3805    }
3806
3807    public LocalPMCache getCache() {
3808        return cache;
3809    }
3810
3811    public void setCache(LocalPMCache cache) {
3812        this.cache = cache;
3813    }
3814
3815    public MemQueryCompiler getMemQueryCompiler() {
3816        return memQueryCompiler;
3817    }
3818
3819    public Reference JavaDoc getActiveReference() {
3820        return activeReference;
3821    }
3822
3823    public void setActiveReference(Reference JavaDoc activeReference) {
3824        this.activeReference = activeReference;
3825    }
3826
3827    /**
3828     * Iterate through all the oid-state pairs returned from the server
3829     * for a store operation and update the local states.
3830     * This will also bring back real oids for new oids involved.
3831     */

3832    private void updateOIDsAndDoAutoS(StatesReturned container) {
3833        for (Iterator i = container.iterator(); i.hasNext(); ) {
3834            EntrySet.Entry e = (EntrySet.Entry)i.next();
3835            OID oid = (OID)e.getKey();
3836            State state = (State)e.getValue();
3837
3838            // This gets the sm with the oid from the container.
3839
// This is done for the case of a newOID which is not
3840
// mapped in the cache via its real oid.
3841
// The sm may not be null because the only way for it to have been sent
3842
// to the server for commit was if it was dirty and hence we must have
3843
// a hard refs to it.
3844
PCStateMan sm;
3845            if (oid instanceof NewObjectOID) {
3846                sm = cache.getByNewObjectOID((NewObjectOID)oid);
3847                if (sm == null) {
3848                    sm = cache.getByOID(oid, false);
3849                    if (sm == null) continue;
3850                } else {
3851                    ((NewObjectOID)sm.oid).setRealOid(oid.getRealOID());
3852                }
3853            } else {
3854                sm = cache.getByOID(oid, false);
3855                if (sm == null) continue;
3856            }
3857
3858            // if the state returned is not null then it contains auto set fields that
3859
// needs must be updated the sm's current state.
3860
// this must only happen if retainValues is set to true and the state
3861
// contains autoset fields. version number is a autoset field.
3862
if (state != null) {
3863                sm.updateAutoFields(state);
3864            }
3865        }
3866    }
3867
3868    /**
3869     * Add all the OIDs and States in the container to the cache.
3870     */

3871    public void addToCache(StatesReturned container) {
3872        for (Iterator i = container.iterator(); i.hasNext(); ) {
3873            EntrySet.Entry e = (EntrySet.Entry)i.next();
3874            cache.addStateOnly((OID)e.getKey(), (State)e.getValue());
3875        }
3876    }
3877
3878    /**
3879     * Add all the OIDs and States in the container to the cache. The
3880     * PCStateMan's are kept and returned to prevent the new instances
3881     * being GCed before they are referenced.
3882     */

3883    private PCStateMan[] addToCacheAndManage(StatesReturned container) {
3884        PCStateMan[] smArray = new PCStateMan[1];
3885        PCStateMan[] ans = new PCStateMan[container.size()];
3886        int c = 0;
3887        for (Iterator i = container.iterator(); i.hasNext(); ) {
3888            EntrySet.Entry e = (EntrySet.Entry)i.next();
3889            ans[c++] = cache.add((OID)e.getKey(), (State)e.getValue(), smArray);
3890        }
3891        return ans;
3892    }
3893
3894    /**
3895     * Add all the OIDs and States in the container to the cache and return
3896     * the PCStateMan for the first direct State. This method is specifically written
3897     * to keep a hard ref to created sm so that it can not be gc'd before it is returned.
3898     */

3899    private PCStateMan addAndReturnFirstDirect(StatesReturned container) {
3900        OID firstDirectOID = container.getDirectOID();
3901        if (firstDirectOID == null) {
3902            return null;
3903        }
3904        PCStateMan[] sm = new PCStateMan[1];
3905        cache.add(firstDirectOID, container.get(firstDirectOID), sm);
3906        for (Iterator i = container.iterator(); i.hasNext(); ) {
3907            EntrySet.Entry e = (EntrySet.Entry)i.next();
3908            cache.addStateOnly((OID)e.getKey(), (State)e.getValue());
3909        }
3910        return sm[0];
3911    }
3912
3913    /**
3914     * Add all the OIDs and States in the container to dcs.
3915     */

3916    private void addToDetachStateContainer(StatesReturned container,
3917            DetachStateContainer dcs) {
3918        for (Iterator i = container.iterator(); i.hasNext(); ) {
3919            EntrySet.Entry e = (EntrySet.Entry)i.next();
3920            dcs.add((OID)e.getKey(), (State)e.getValue());
3921        }
3922    }
3923
3924    /**
3925     * The StorageManager calls this method to check if we need prefetched
3926     * data or not.
3927     */

3928    public boolean isStateRequired(OID oid, FetchGroup fetchGroup) {
3929        State state = cache.getStateByOID(oid);
3930        if (state != null) {
3931            if (fetchGroup == null) {
3932                fetchGroup = state.getClassMetaData().fetchGroups[0];
3933            }
3934            return !state.containsFetchGroup(fetchGroup);
3935        }
3936        return true;
3937    }
3938
3939}
3940
3941
Popular Tags