KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > sqlstore > impl > PersistenceManagerImpl


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * PersistenceManagerimpl.java
26  *
27  * Created on March 6, 2000
28  */

29
30 package com.sun.jdo.spi.persistence.support.sqlstore.impl;
31
32 import com.sun.jdo.api.persistence.support.*;
33 import com.sun.jdo.api.persistence.support.Transaction;
34 import com.sun.jdo.spi.persistence.support.sqlstore.*;
35 import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceCapable;
36 import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManager;
37 import com.sun.jdo.spi.persistence.support.sqlstore.PersistenceManagerFactory;
38 import com.sun.jdo.spi.persistence.support.sqlstore.ejb.EJBHelper;
39 import com.sun.jdo.spi.persistence.support.sqlstore.query.QueryImpl;
40 import com.sun.jdo.spi.persistence.utility.I18NHelper;
41 import com.sun.jdo.spi.persistence.utility.NullSemaphore;
42 import com.sun.jdo.spi.persistence.utility.Semaphore;
43 import com.sun.jdo.spi.persistence.utility.SemaphoreImpl;
44 import com.sun.jdo.spi.persistence.utility.logging.Logger;
45
46 import javax.transaction.Status JavaDoc;
47 import java.io.File JavaDoc;
48 import java.io.FilenameFilter JavaDoc;
49 import java.lang.reflect.Constructor JavaDoc;
50 import java.lang.reflect.Field JavaDoc;
51 import java.util.*;
52
53 public class PersistenceManagerImpl implements PersistenceManager {
54     /**
55      * True if this PersistenceManager is closed
56      */

57     private boolean _isClosed = true;
58
59     // Current wrapper
60
private PersistenceManagerWrapper current = null;
61
62     // Reference to the associated JTA Transaction if any
63
private javax.transaction.Transaction JavaDoc _jta = null;
64
65     /**
66      * Reference to global PersistenceStore
67      */

68     private PersistenceStore _store = null;
69
70     /**
71      * Associated Transaction
72      */

73     private TransactionImpl _transaction = null;
74
75     /**
76      * PersistenceManagerFactory that created (and could be pooling)
77      * this PersistenceManager
78      */

79     private PersistenceManagerFactory persistenceManagerFactory = null;
80
81
82     /**
83      * List of all Persistent instances used
84      * in this Transaction not yet flushed to the datastore.
85      */

86     private List _txCache;
87
88     /**
89      * List of all Persistent instances used
90      * in this Transaction.
91      */

92     private Set _flushedCache;
93
94     /**
95      * Map of Persistent instances accessed by this PersistenceManager. Ideally it should be
96      * a weak-value HashMap to allow for garbage collection of instances that are not
97      * referenced any more. java.util.WeakHashMap is a weak-key HashMap and thus does not
98      * solve this purpose.
99      */

100     private Map _weakCache;
101
102     /**
103      * Intended to be set to true if there is an exception during flush in
104      * {@link #beforeCompletion}. If true, then the Version Consistency cache
105      * should be have instances removed during
106      * {@link #afterCompletion}.
107      */

108     private boolean cleanupVersionConsistencyCache = false;
109
110     //
111
// Properties for controlling construction of caches.
112
// For the integer properties, we can use Integer.getInteger. There is
113
// no corresponding method for floats :-(
114
//
115

116     /**
117      * Properties with "dirtyCache" in their name apply to the _txCache.
118      * This initializes the _txCache's initialCapacity. If unspecified, uses
119      * 20.
120      */

121     private static final int _txCacheInitialCapacity = Integer.getInteger(
122       "com.sun.jdo.api.persistence.support.PersistenceManager.dirtyCache.initialCapacity", // NOI18N
123
20).intValue();
124
125     /**
126      * Properties with "transactionalCache" in their name apply to the _flushedCache.
127      * This initializes the _flushedCache's initialCapacity. If unspecified,
128      * uses 20.
129      */

130     private static final int _flushedCacheInitialCapacity = Integer.getInteger(
131       "com.sun.jdo.api.persistence.support.PersistenceManager.transactionalCache.initialCapacity", // NOI18N
132
20).intValue();
133
134     /**
135      * Properties with "transactionalCache" in their name apply to the _flushedCache.
136      * This initializes the _flushedCache's loadFactor. If unspecified, uses
137      * 0.75, which is the default load factor for a HashSet.
138      */

139     private static final float _flushedCacheLoadFactor;
140
141     static {
142         float f = (float) 0.75;
143         try {
144             f =
145                 Float.valueOf(
146                   System.getProperty(
147                     "com.sun.jdo.api.persistence.support.PersistenceManager.transactionalCache.loadFactor", // NOI18N
148
"0.75")).floatValue(); // NOI18N
149
} finally {
150             _flushedCacheLoadFactor = f;
151         }
152     }
153
154     /**
155      * Properties with "globalCache" in their name apply to the _weakCache.
156      * This initializes the _weakCache's initialCapacity. If unspecified,
157      * uses 20.
158      */

159     private static final int _weakCacheInitialCapacity = Integer.getInteger(
160       "com.sun.jdo.api.persistence.support.PersistenceManager.globalCache.initialCapacity", // NOI18N
161
20).intValue();
162
163     /**
164      * Properties with "globalCache" in their name apply to the _weakCache.
165      * This initializes the _weakCache's loadFactor. If unspecified, uses
166      * 0.75, which is the default load factor for a WeakHashMap.
167      */

168     private static final float _weakCacheLoadFactor;
169
170     static {
171         float f = (float) 0.75;
172         try {
173             f =
174                 Float.valueOf(
175                   System.getProperty(
176                     "com.sun.jdo.api.persistence.support.PersistenceManager.globalCache.loadFactor", // NOI18N
177
"0.75")).floatValue(); // NOI18N
178
} finally {
179             _weakCacheLoadFactor = f;
180         }
181     }
182
183     /** Collection of Query instances created for this pm. */
184     private Collection queries = new ArrayList();
185
186     /**
187      * Flag for Query
188      */

189     private boolean _ignoreCache = true;
190
191     /**
192      * Flag for optimistic transaction
193      */

194     private boolean _optimistic = true;
195
196     /**
197      * Flag for supersedeDeletedInstance
198      */

199     private boolean _supersedeDeletedInstance = true;
200
201     /**
202      * Flag for requireCopyObjectId
203      */

204     private boolean _requireCopyObjectId = true;
205
206     /**
207      * Flag for requireTrackedSCO
208      */

209     private boolean _requireTrackedSCO = true;
210
211     /**
212      * Flag for nontransactionalRead
213      */

214     private boolean _nontransactionalRead = true;
215
216     /**
217      * Flag for active transaction
218      */

219     private boolean _activeTransaction = false;
220
221     /**
222      * User Object
223      */

224     private Object JavaDoc _userObject = null;
225
226     /**
227      * Flag for commit process
228      */

229     private boolean _insideCommit = false;
230
231     /**
232      * Flag for flush processing
233      */

234     private boolean _insideFlush = false;
235
236     /**
237      * Pattern for OID class names
238      */

239     private static final String JavaDoc oidName_OID = "OID";// NOI18N
240
private static final String JavaDoc oidName_KEY = "KEY";// NOI18N
241

242     /**
243      * Properies object
244      */

245     private Properties _properties = null;
246
247     /**
248      * PC Constructor signature
249      */

250     private static final Class JavaDoc[] sigSM = new Class JavaDoc[]{
251         StateManager.class};
252
253     /**
254      * Lock used for synchronizing access to the _txCache and _weakCache
255      */

256     private final Semaphore _cacheLock;
257
258     /**
259      * Lock used for synchronizing field updates. It should be used
260      * at the discretion of the StateManager.
261      */

262     private final Semaphore _fieldUpdateLock;
263
264     /**
265      * Lock used for implementing read-write barrier.
266      */

267     private Object JavaDoc _readWriteLock = new Object JavaDoc();
268
269     /**
270      * The count for the current reader (> 0) or writer (< 0)
271      * Note that the exclusive lock can go multi-level deep
272      * as long as the same thread is acquiring it.
273      */

274     private long _readWriteCount = 0;
275
276     /**
277      * The number of threads that are currently waiting on
278      * the _readWriteLock.
279      */

280     private long _waiterCount = 0;
281
282     /**
283      * The thread that has the write (exclusive) lock.
284      */

285     private Thread JavaDoc _exclusiveLockHolder = null;
286
287     /** Indicates if this PM is running in a multithreaded environment, i.e.,
288      * if it has to do locking.
289      */

290     private final boolean _multithreaded;
291
292     /**
293      * The logger
294      */

295     private static Logger logger = LogHelperPersistenceManager.getLogger();
296
297     /**
298      * I18N message handler
299      */

300     private final static ResourceBundle messages = I18NHelper.loadBundle(
301             "com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
302
PersistenceManagerImpl.class.getClassLoader());
303
304     /**
305      * Constructor
306      */

307     PersistenceManagerImpl(PersistenceManagerFactory pmf, javax.transaction.Transaction JavaDoc t,
308                            String JavaDoc username, String JavaDoc password) {
309         persistenceManagerFactory = pmf;
310
311         // Initialize caches as per property values.
312
if (logger.isLoggable(Logger.FINEST)) {
313             Object JavaDoc[] items = new Object JavaDoc[] { new Integer JavaDoc(_txCacheInitialCapacity),
314                                             new Integer JavaDoc(_flushedCacheInitialCapacity),
315                                             new Float JavaDoc(_flushedCacheLoadFactor),
316                                             new Integer JavaDoc(_weakCacheInitialCapacity),
317                                             new Float JavaDoc(_weakCacheLoadFactor) };
318             logger.finest("sqlstore.persistencemgr.cacheproperties", items); // NOI18N
319
}
320         _txCache = new ArrayList(_txCacheInitialCapacity);
321         _flushedCache = new LinkedHashSet(_flushedCacheInitialCapacity, _flushedCacheLoadFactor);
322         _weakCache = new HashMap(_weakCacheInitialCapacity, _weakCacheLoadFactor);
323
324         // create new Transaction object and set defaults
325

326         _transaction = new TransactionImpl(this,
327                 username, password, TransactionImpl.TRAN_DEFAULT_TIMEOUT); // VERIFY!!!!
328

329         _ignoreCache = pmf.getIgnoreCache();
330         _optimistic = pmf.getOptimistic();
331         _nontransactionalRead = pmf.getNontransactionalRead();
332         _supersedeDeletedInstance = pmf.getSupersedeDeletedInstance();
333         _requireCopyObjectId = pmf.getRequireCopyObjectId();
334         _requireTrackedSCO = pmf.getRequireTrackedSCO();
335
336         this._jta = t; // if null, nothing is changed
337
_isClosed = false;
338
339         _multithreaded = ( ! EJBHelper.isManaged());
340
341         if (_multithreaded) {
342             _cacheLock =
343                 new SemaphoreImpl("PersistenceManagerImpl.cacheLock"); // NOI18N
344
_fieldUpdateLock =
345                 new SemaphoreImpl("PersistenceManagerImpl.fieldUpdateLock"); // NOI18N
346
} else {
347             if (_jta == null) {
348                 // Non-transactional PersistenceManager can be used in a multithreaded
349
// environment.
350
_cacheLock =
351                     new SemaphoreImpl("PersistenceManagerImpl.cacheLock"); // NOI18N
352
} else {
353                 _cacheLock =
354                     new NullSemaphore("PersistenceManagerImpl.cacheLock"); // NOI18N
355
}
356             _fieldUpdateLock =
357                 new NullSemaphore("PersistenceManagerImpl.fieldUpdateLock"); // NOI18N
358
}
359     }
360
361     /**
362      *
363      */

364     protected void setStore(PersistenceStore store) {
365         _store = store;
366     }
367
368     /**
369      *
370      */

371     protected PersistenceStore getStore() {
372         return _store;
373     }
374
375     /**
376      *
377      */

378     protected boolean getIgnoreCache() {
379         return _ignoreCache;
380     }
381
382     /**
383      *
384      */

385     protected boolean verify(String JavaDoc username, String JavaDoc password) {
386         return _transaction.verify(username, password);
387     }
388
389     /**
390      *
391      */

392     public boolean isClosed() {
393         return _isClosed;
394     }
395
396     /**
397      * Force to close the persistence manager. Called by
398      * TransactionImpl.afterCompletion in case of the CMT transaction
399      * and the status value passed to the method cannot be resolved.
400      */

401     public void forceClose() {
402
403         // Return to pool - TBD if we use pooling of free PMs.
404
//persistenceManagerFactory.returnToPool((com.sun.jdo.api.persistence.support.PersistenceManager)this);
405

406         persistenceManagerFactory.releasePersistenceManager(this, _jta);
407
408         // Closing PMWrappers need isClosed() to return true to avoid
409
// endless recursion - last PMWrapper tries to close PM.
410
_isClosed = true;
411         while (current != null) {
412             current.close();
413         }
414
415         Collection c = _weakCache.values();
416         for (Iterator it = c.iterator(); it.hasNext();) {
417             StateManager sm = (StateManager)it.next();
418
419             // RESOLVE - do we want to release all references in SM?
420
// 1 of two calls below should be removed.
421

422             // Only nullify PM reference in SM.
423
//sm.setPersistenceManager(null);
424

425             // Nullify all references in SM.
426
sm.release(); // This requires 'release()' to be added to SM interface.
427
}
428
429         disconnectQueries();
430
431         persistenceManagerFactory = null;
432         _jta = null;
433
434         _weakCache.clear();
435         _txCache.clear();
436         _flushedCache.clear();
437
438         _flushedCache = null;
439         _txCache = null;
440         _weakCache = null;
441
442         _store = null;
443         _transaction = null;
444
445         _exclusiveLockHolder = null;
446     }
447
448     /**
449      * close the persistence manager
450      */

451     public void close() {
452
453         acquireExclusiveLock();
454
455         try {
456             if (_jta != null) {
457                 // Called by the transaction completion - deregister.
458
persistenceManagerFactory.releasePersistenceManager(this, _jta);
459                 _jta = null;
460             }
461
462             if (current != null && _transaction.getTransactionType() != TransactionImpl.CMT) {
463                 /*
464                                   if (_transaction.getTransactionType() == TransactionImpl.BMT_JDO) {
465                                   persistenceManagerFactory.releasePersistenceManager(this, _jta);
466                                   _jta = null;
467                                   }
468                                 */

469                 return; // or throw an exception ???
470
}
471
472             if (_activeTransaction || _flushedCache.size() > 0) {
473                 throw new JDOException(I18NHelper.getMessage(messages,
474                         "jdo.persistencemanagerimpl.close.activetransaction"));// NOI18N
475
}
476
477             forceClose();
478
479         } finally {
480             releaseExclusiveLock();
481         }
482     }
483
484
485     /**
486      * Returns transaction associated with this persistence manager
487      * @return transaction current transaction
488      */

489     public Transaction currentTransaction() {
490         assertIsOpen();
491         return _transaction;
492     }
493
494
495     /** Create a new Query with no elements.
496      * @return a new Query instance with no elements.
497      */

498     public Query newQuery() {
499         assertIsOpen();
500         QueryImpl q = new QueryImpl(this);
501         registerQuery(q);
502         return q;
503     }
504
505     /** Create a new Query using elements from another Query. The other Query
506      * must have been created by the same JDO implementation. It might be active
507      * in a different PersistenceManager or might have been serialized and
508      * restored.
509      * @return the new Query
510      * @param compiled another Query from the same JDO implementation
511      */

512     public Query newQuery(Object JavaDoc compiled) {
513         assertIsOpen();
514         QueryImpl q = new QueryImpl(this, compiled);
515         registerQuery(q);
516         return q;
517     }
518
519     /** Create a new Query specifying the Class of the results.
520      * @param cls the Class of the results
521      * @return the new Query
522      */

523     public Query newQuery(Class JavaDoc cls) {
524         assertIsOpen();
525         QueryImpl q = new QueryImpl(this, cls);
526         registerQuery(q);
527         return q;
528     }
529
530     /** Create a new Query with the Class of the results and candidate Collection.
531      * specified.
532      * @param cls the Class of results
533      * @param cln the Collection of candidate instances
534      * @return the new Query
535      */

536     public Query newQuery(Class JavaDoc cls, Collection cln) {
537         assertIsOpen();
538         QueryImpl q = new QueryImpl(this, cls, cln);
539         registerQuery(q);
540         return q;
541     }
542
543     /** Create a new Query with the Class of the results and Filter.
544      * specified.
545      * @param cls the Class of results
546      * @param filter the Filter for candidate instances
547      * @return the new Query
548      */

549     public Query newQuery(Class JavaDoc cls, String JavaDoc filter) {
550         assertIsOpen();
551         QueryImpl q = new QueryImpl(this, cls, filter);
552         registerQuery(q);
553         return q;
554     }
555
556     /** Create a new Query with the Class of the results, candidate Collection,
557      * and Filter.
558      * @param cls the Class of results
559      * @param cln the Collection of candidate instances
560      * @param filter the Filter for candidate instances
561      * @return the new Query
562      */

563     public Query newQuery(Class JavaDoc cls, Collection cln, String JavaDoc filter) {
564         assertIsOpen();
565         QueryImpl q = new QueryImpl(this, cls, cln, filter);
566         registerQuery(q);
567         return q;
568     }
569
570     /** The PersistenceManager may manage a collection of instances in the data
571      * store based on the class of the instances. This method returns a
572      * Collection of instances in the data store that might be iterated or
573      * given to a Query as the Collection of candidate instances.
574      * @param persistenceCapableClass Class of instances
575      * @param subclasses whether to include instances of subclasses
576      * @return a Collection of instances
577      * @see #newQuery
578      */

579     public Collection getExtent(Class JavaDoc persistenceCapableClass,
580                                 boolean subclasses) {
581         assertIsOpen();
582         return new ExtentCollection(this, persistenceCapableClass, subclasses);
583     }
584
585     /** This method locates a persistent instance in the cache of instances
586      * managed by this PersistenceManager. If an instance with the same ObjectId
587      * is found it is returned. Otherwise, a new instance is created and
588      * associated with the ObjectId.
589      *
590      * <P>If the instance does not exist in the data store, then this method will
591      * not fail. However, a request to access fields of the instance will
592      * throw an exception.
593      * @see #getObjectById(Object, boolean)
594      * @param oid an ObjectId
595      * @return the PersistenceCapable instance with the specified
596      * ObjectId
597      */

598     public Object JavaDoc getObjectById(Object JavaDoc oid) {
599         return getObjectById(oid, false);
600     }
601
602     /** This method locates a persistent instance in the cache of instances
603      * managed by this <code>PersistenceManager</code>.
604      * The <code>getObjectByIdInternal</code> method attempts
605      * to find an instance in the cache with the specified JDO identity.
606      * <P>If the <code>PersistenceManager</code> is unable to resolve the <code>oid</code> parameter
607      * to an ObjectId instance, then it throws a <code>JDOUserException</code>.
608      * <P>If the <code>validate</code> flag is <code>false</code>, and there is already an instance in the
609      * cache with the same JDO identity as the <code>oid</code> parameter, then this method
610      * returns it. There is no change made to the state of the returned
611      * instance.
612      * <P>If there is not an instance already in the cache with the same JDO
613      * identity as the <code>oid</code> parameter, then this method creates an instance
614      * with the specified JDO identity and returns it. If there is no
615      * transaction in progress, the returned instance will be hollow.
616      * <P>If there is a transaction in progress, the returned instance will
617      * persistent-nontransactional in an optimistic transaction, or persistent-clean in a
618      * datastore transaction.
619      * @return the <code>PersistenceCapable</code> instance with the specified ObjectId
620      * @param oid an ObjectId
621      * @param validate if the existence of the instance is to be validated
622      */

623     public Object JavaDoc getObjectById(Object JavaDoc oid, boolean validate) {
624         boolean debug = logger.isLoggable(Logger.FINEST);
625
626         assertIsOpen();
627         assertActiveTransaction(true);
628
629         Object JavaDoc rc = null;
630
631         if (debug) {
632             Object JavaDoc[] items = new Object JavaDoc[] {oid, this,_jta};
633             logger.finest("sqlstore.persistencemgr.getbyobjid", items); // NOI18N
634
}
635
636         if (oid == null)
637             return null;
638
639         StateManager sm = lookupObjectById(oid, null);
640         rc = sm.getPersistent();
641         if (!JDOHelper.isTransactional(rc)) {
642
643             // Instance was not found in _weakCache, or the found instance is
644
// non transactional. Check the version consistency cache.
645
boolean foundInstance = initializeFromVersionConsistencyCache(sm);
646
647             if (validate && !foundInstance) {
648
649                 // Not found in the cache, or non transactional.
650
try {
651                     sm.reload();
652
653                 } catch (JDOException e) {
654                     if (!sm.isValid()) {
655                         // This StateManager had never been used before.
656
deregisterInstance(oid);
657                         sm.release();
658                     }
659
660                     throw e;
661                 } catch (Exception JavaDoc e) {
662                     throw new JDOUserException(I18NHelper.getMessage(messages,
663                        "jdo.persistencemanagerimpl.fetchinstance.none"), e);// NOI18N
664
}
665             }
666         }
667
668         sm.setValid();
669         return rc;
670     }
671
672     /**
673      * Called internally by <code>RetrieveDesc</code> to lookup an instance
674      * in the cache, or prepare new instance to be populated with values from the datastore.
675      * @return the <code>StateManager</code> instance with the specified ObjectId
676      * @param oid an ObjectId
677      * @param pcClass the Class type of the PersistenceCapable instance to be associated
678      * with this StateManager.
679      */

680     public StateManager findOrCreateStateManager(Object JavaDoc oid, Class JavaDoc pcClass) {
681         return lookupObjectById(oid, pcClass);
682     }
683
684     /** This is the actual implementation of the #getObjectById(Object oid, validate) and
685      * #getObjectByIdInternal(Object oid, Class pcClass).
686      * @param oid an ObjectId
687      * @param classType the Class type of the returned object or null if not known.
688      */

689     private StateManager lookupObjectById(Object JavaDoc oid, Class JavaDoc classType) {
690         StateManager sm = null;
691
692         // Check the _weakCache for the instance
693
try {
694             acquireCacheLock();
695
696             sm = (StateManager)_weakCache.get(oid);
697             if (sm == null) {
698                 boolean external = false;
699                 // Do NOT look in DB, but create a Hollow instance:
700
if (classType == null) {
701                     classType = loadClassForOid(oid);
702
703                     if (classType == null) {
704                         // Class not found, report an error
705
throw new JDOUserException(I18NHelper.getMessage(messages,
706                                 "jdo.persistencemanagerimpl.getobjectbyid.nometadata"), // NOI18N
707
new Object JavaDoc[]{oid});
708                     }
709                     external = true;
710                 }
711
712                 try {
713                     // create new instance and register it
714
sm = createStateManager(classType);
715                     if (external) {
716                         // oid needs to be cloned for extenral cases
717
// as the user might modify oid
718
oid = internalCloneOid(oid, sm);
719                     }
720                     sm.setObjectId(oid);
721                     setKeyFields(sm);
722
723                     if (external) {
724                         sm.initialize(false);
725                     } else {
726                         // put it in the weak cache only as it is Hollow.
727
_weakCache.put(oid, sm);
728                     }
729                 } catch (JDOException e) {
730                     throw e;
731                 } catch (Exception JavaDoc e) {
732                     throw new JDOUserException(I18NHelper.getMessage(messages,
733                             "jdo.persistencemanagerimpl.fetchinstance.none"), e);// NOI18N
734
}
735             }
736         } finally {
737             releaseCacheLock();
738         }
739
740         return sm;
741     }
742
743     /**
744      * Create a StateManager.
745      * @param classType Class of the PersistenceCapable.
746      */

747     private StateManager createStateManager(Class JavaDoc classType) {
748         StateManager rc = _store.getStateManager(classType);
749         newInstance(rc);
750
751         return rc;
752     }
753
754     /** The ObjectId returned by this method represents the JDO identity of
755      * the instance. The ObjectId is a copy (clone) of the internal state
756      * of the instance, and changing it does not affect the JDO identity of
757      * the instance.
758      * Delegates actual execution to the internal method.
759      * @param pc the PersistenceCapable instance
760      * @return the ObjectId of the instance
761      */

762     public Object JavaDoc getObjectId(Object JavaDoc pc) {
763         boolean debug = logger.isLoggable(Logger.FINEST);
764
765         assertIsOpen();
766         assertActiveTransaction(true);
767
768         if (debug) {
769             Object JavaDoc[] items = new Object JavaDoc[] {Thread.currentThread(),pc, this, _jta};
770             logger.finest("sqlstore.persistencemgr.getobjid",items); // NOI18N
771
}
772
773         try {
774             assertPersistenceCapable(pc);
775         } catch (Exception JavaDoc e) {
776             if (debug) {
777                 Object JavaDoc[] items = new Object JavaDoc[] {pc, this};
778                 logger.finest("sqlstore.persistencemgr.getobjid.notpc",items); // NOI18N
779
}
780
781             return null;
782         }
783
784         StateManager sm = ((PersistenceCapable)pc).jdoGetStateManager();
785         if (sm == null) {
786             // Not persistent
787
return null;
788
789         } else if (sm.getPersistenceManagerInternal() != this) {
790             if (debug) {
791                 Object JavaDoc[] items = new Object JavaDoc[] {pc, this, _jta};
792                 logger.finest("sqlstore.persistencemgr.getobjid.notpm",items); // NOI18N
793
}
794
795             return null;
796         }
797
798         return internalGetObjectId(sm);
799     }
800
801     /** This method is used to get a PersistenceCapable instance
802      * representing the same data store object as the parameter, that is valid
803      * for this PersistenceManager.
804      * @param pc a PersistenceCapable instance
805      * @return the PersistenceCapable instance representing the
806      * same data store object
807      */

808     public Object JavaDoc getTransactionalInstance(Object JavaDoc pc) {
809         assertIsOpen();
810         assertActiveTransaction(false);
811         if (!(pc instanceof PersistenceCapable)) {
812             return pc;
813         }
814
815         PersistenceCapable mypc = (PersistenceCapable) pc;
816
817         // The PC.jdoGetPersistenceManager() returns PersistenceManagerWrapper:
818
PersistenceManagerWrapper pmw = (PersistenceManagerWrapper) mypc.jdoGetPersistenceManager();
819         PersistenceManagerImpl pm = (PersistenceManagerImpl) pmw.getPersistenceManager();
820
821         if (pm == null || pm == this) {
822             return pc;
823         }
824
825         return getObjectById(pm.internalGetObjectId(mypc.jdoGetStateManager()));
826     }
827
828     /** Make the transient instance persistent in this PersistenceManager.
829      * This method must be called in an active transaction.
830      * The PersistenceManager assigns an ObjectId to the instance and
831      * transitions it to persistent-new.
832      * The instance will be managed in the Extent associated with its Class.
833      * The instance will be put into the data store at commit.
834      * @param pc a transient instance of a Class that implements
835      * PersistenceCapable
836      */

837     public void makePersistent(Object JavaDoc pc) {
838         boolean debug = logger.isLoggable(Logger.FINEST);
839
840         if (debug)
841             {
842             Object JavaDoc[] items = new Object JavaDoc[] {Thread.currentThread(), pc, this, _jta};
843             logger.finest("sqlstore.persistencemgr.makepersistent",items); // NOI18N
844
}
845
846         if (pc == null)
847             return; // ignore
848

849         acquireShareLock();
850         try {
851             assertIsOpen();
852             assertActiveTransaction(false);
853             assertPersistenceCapable(pc);
854             internalMakePersistent((PersistenceCapable) pc);
855             if (debug)
856                 {
857                  Object JavaDoc[] items = new Object JavaDoc[] {pc, this, _jta};
858                  logger.finest("sqlstore.persistencemgr.makepersistent.done",items); // NOI18N
859
}
860
861         } finally {
862             releaseShareLock();
863         }
864     }
865
866     /** Make an array of instances persistent.
867      * @param pcs an array of transient instances
868      * @see #makePersistent(Object pc)
869      */

870     public void makePersistent(Object JavaDoc[] pcs) {
871         if (pcs == null)
872             return; // ignore
873

874         for (int i = 0; i < pcs.length; i++) {
875             makePersistent(pcs[i]);
876         }
877     }
878
879     public void makePersistent(Collection pcs) {
880         if (pcs == null)
881             return; // ignore
882

883         makePersistent(pcs.toArray());
884     }
885
886     public void deletePersistent(Object JavaDoc pc) {
887         if (pc == null)
888             return; // ignore
889

890         acquireShareLock();
891
892         try {
893             assertIsOpen();
894             assertActiveTransaction(false);
895             assertPersistenceCapable(pc);
896             internalDeletePersistent((PersistenceCapable) pc);
897         } finally {
898             releaseShareLock();
899         }
900     }
901
902     public void deletePersistent(Object JavaDoc[] pcs) {
903         if (pcs == null)
904             return; // ignore
905

906         for (int i = 0; i < pcs.length; i++) {
907             deletePersistent(pcs[i]);
908         }
909     }
910
911     public void deletePersistent(Collection pcs) {
912         if (pcs == null)
913             return; // ignore
914

915         deletePersistent(pcs.toArray());
916     }
917
918
919     /** This method returns the PersistenceManagerFactory used to create
920      * this PersistenceManager. It returns null if this instance was
921      * created via a constructor.
922      * @return the PersistenceManagerFactory that created
923      * this PersistenceManager
924      */

925     public com.sun.jdo.api.persistence.support.PersistenceManagerFactory getPersistenceManagerFactory() {
926         return persistenceManagerFactory;
927     }
928
929     void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
930         if (persistenceManagerFactory == null)
931             persistenceManagerFactory = pmf;
932     }
933
934     /** The application can manage the PersistenceManager instances
935      * more easily by having an application object associated with each
936      * PersistenceManager instance.
937      * @param o the user instance to be remembered by the PersistenceManager
938      * @see #getUserObject
939      */

940     public void setUserObject(Object JavaDoc o) {
941         this._userObject = o;
942     }
943
944     /** The application can manage the PersistenceManager instances
945      * more easily by having an application object associated with each
946      * PersistenceManager instance.
947      * @return the user object associated with this PersistenceManager
948      * @see #setUserObject
949      */

950     public Object JavaDoc getUserObject() {
951         return _userObject;
952     }
953
954     /** The JDO vendor might store certain non-operational properties and
955      * make those properties available to applications (for troubleshooting).
956      *
957      * <P>Standard properties include:
958      * <li>VendorName</li>
959      * <li>VersionNumber</li>
960      * @return the Properties of this PersistenceManager
961      */

962     public Properties getProperties() {
963         if (_properties == null) {
964             _properties = RuntimeVersion.getVendorProperties(
965                     "/com/sun/jdo/spi/persistence/support/sqlstore/sys.properties");// NOI18N
966
}
967         return _properties;
968     }
969
970     /**
971      * Returns the boolean value of the supersedeDeletedInstance flag
972      * for this PersistenceManager. If set to true, deleted instances are
973      * allowed to be replaced with persistent-new instances with the equal
974      * Object Id.
975      * @return boolean supersedeDeletedInstance flag
976      */

977     public boolean getSupersedeDeletedInstance () {
978         return _supersedeDeletedInstance;
979     }
980
981
982     /**
983      * Sets the supersedeDeletedInstance flag for this PersistenceManager.
984      * @param flag boolean supersedeDeletedInstance flag
985      */

986     public void setSupersedeDeletedInstance (boolean flag) {
987         // RESOLVE: synchronization
988
_supersedeDeletedInstance = flag;
989     }
990
991     /**
992      * Returns the boolean value of the requireCopyObjectId flag
993      * for this PersistenceManager. If set to false, the PersistenceManager
994      * does not create a copy of an ObjectId for <code>PersistenceManager.getObjectId(Object pc)</code>
995      * and <code>PersistenceManager.getObjectById(Object oid)</code> requests.
996      *
997      * @see PersistenceManager#getObjectId(Object pc)
998      * @see PersistenceManager#getObjectById(Object oid)
999      * @return boolean requireCopyObjectId flag
1000     */

1001    public boolean getRequireCopyObjectId() {
1002        return _requireCopyObjectId;
1003    }
1004
1005
1006    /**
1007     * Sets the requireCopyObjectId flag for this PersistenceManager.
1008     * If set to false, the PersistenceManager will not create a copy of
1009     * an ObjectId for <code>PersistenceManager.getObjectId(Object pc)</code>
1010     * and <code>PersistenceManager.getObjectById(Object oid)</code> requests.
1011     *
1012     * @see PersistenceManager#getObjectId(Object pc)
1013     * @see PersistenceManager#getObjectById(Object oid)
1014     * @param flag boolean requireCopyObjectId flag
1015     */

1016    public void setRequireCopyObjectId (boolean flag) {
1017        // RESOLVE: synchronization
1018
_requireCopyObjectId = flag;
1019    }
1020
1021    /**
1022     * Returns the boolean value of the requireTrackedSCO flag
1023     * for this PersistenceManager. If set to false, this PersistenceManager
1024     * will not create tracked SCO instances for
1025     * new persistent instances at commit with retainValues set to true
1026     * and while retrieving data from a datastore.
1027     *
1028     * @return boolean requireTrackedSCO flag
1029     */

1030    public boolean getRequireTrackedSCO() {
1031        return _requireTrackedSCO;
1032    }
1033
1034    /**
1035     * Sets the requireTrackedSCO flag for this PersistenceManager.
1036     * If set to false, this PersistenceManager will not create tracked
1037     * SCO instances for new persistent instances at commit with retainValues
1038     * set to true and while retrieving data from a datastore.
1039     *
1040     * @param flag boolean requireTrackedSCO flag
1041     */

1042    public void setRequireTrackedSCO (boolean flag) {
1043        // RESOLVE: synchronization
1044
_requireTrackedSCO = flag;
1045    }
1046
1047    /** In order for the application to construct instance of the ObjectId class
1048     * it needs to know the class being used by the JDO implementation.
1049     * @param cls the PersistenceCapable Class
1050     * @return the Class of the ObjectId of the parameter
1051     */

1052    public Class JavaDoc getObjectIdClass(Class JavaDoc cls) {
1053        PersistenceConfig config = loadPersistenceConfig(cls);
1054        return config.getOidClass();
1055    }
1056
1057    /**
1058     * Returns a new instance of the object defined by the given
1059     * StateManager
1060     * @param sm StateManager
1061     * @return new instance of the object
1062     */

1063    public Object JavaDoc newInstance(StateManager sm) {
1064        Object JavaDoc o = null;
1065
1066        PersistenceConfig config = sm.getPersistenceConfig();
1067
1068        if (config == null) {
1069            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
1070                    "jdo.persistencemanagerimpl.newinstance.badsm"));// NOI18N
1071
}
1072
1073        Class JavaDoc type = config.getPersistenceCapableClass();
1074
1075        try {
1076            Constructor JavaDoc constr = type.getConstructor(sigSM);
1077
1078            if (constr != null) {
1079                o = constr.newInstance(new Object JavaDoc[]{sm});
1080
1081                // Initalize the state manager to reference this pm and the newly created instance
1082
sm.setPersistenceManager(this);
1083                sm.setPersistent(o);
1084            }
1085        } catch (Exception JavaDoc e) {
1086            throw new JDOFatalUserException(I18NHelper.getMessage(messages,
1087                    "jdo.persistencemanagerimpl.assertpersistencecapable.error", // NOI18N
1088
type.getName()), e);
1089        }
1090
1091        return o;
1092    }
1093
1094    /**
1095     * Executes the given retrieve descriptor. The result
1096     * is a collection unless an aggregate query was specified.
1097     * In most cases the query result is a collection of
1098     * persistent objects. In case of a projection
1099     * on a local field the collection holds objects of that
1100     * type. For aggregate queries the result is a
1101     * single object, which type was defined by the caller.
1102     *
1103     * @param action The retrieve descriptor.
1104     * @param parameters The input parameters for the query.
1105     * @return A collection of (persistent) objects unless
1106     * an aggregate query was specified.
1107     */

1108    public Object JavaDoc retrieve(RetrieveDesc action, ValueFetcher parameters)
1109    {
1110        acquireShareLock();
1111
1112        try {
1113            assertActiveTransaction(true);
1114            return _store.retrieve(this, action, parameters);
1115        } finally {
1116            releaseShareLock();
1117        }
1118    }
1119
1120    /**
1121     * Executes the given retrieve descriptor. The result
1122     * is a collection unless an aggregate query was specified.
1123     * In most cases the query result is a collection of
1124     * persistent objects. In case of a projection
1125     * on a local field the collection holds objects of that
1126     * type. For aggregate queries the result is a
1127     * single object, which type was defined by the caller.
1128     *
1129     * @param action The retrieve descriptor.
1130     * @return A collection of (persistent) objects unless
1131     * an aggregate query was specified.
1132     */

1133    public Object JavaDoc retrieve(RetrieveDesc action) {
1134        return retrieve(action, null);
1135    }
1136
1137    /**
1138     * Return a RetrieveDesc given a Class object.
1139     */

1140    public RetrieveDesc getRetrieveDesc(Class JavaDoc classType) {
1141        acquireShareLock();
1142
1143        try {
1144            loadPersistenceConfig(classType);
1145            return _store.getRetrieveDesc(classType);
1146        } finally {
1147            releaseShareLock();
1148        }
1149    }
1150
1151    /**
1152     * Return a RetrieveDesc for a foreign field (relationship) given the
1153     * Class object for the parent class.
1154     */

1155    public RetrieveDesc getRetrieveDesc(String JavaDoc fieldName, Class JavaDoc classType) {
1156        acquireShareLock();
1157
1158        try {
1159            loadPersistenceConfig(classType);
1160            return _store.getRetrieveDesc(fieldName, classType);
1161        } finally {
1162            releaseShareLock();
1163        }
1164    }
1165
1166
1167    /**
1168     * Register instance in the weak cache only. Used to restore persistent instance
1169     * at the rollback if it was replaced during transaction execution with another
1170     * instance with the same object Id.
1171     */

1172    public void registerInstance(StateManager sm, Object JavaDoc oid) {
1173        boolean debug = logger.isLoggable(Logger.FINEST);
1174        if (debug)
1175            {
1176            Object JavaDoc[] items = new Object JavaDoc[] {Thread.currentThread(), oid, this, _jta};
1177            logger.finest("sqlstore.persistencemgr.registerinstance",items); // NOI18N
1178
}
1179
1180        try {
1181            acquireCacheLock();
1182            if (debug)
1183                logger.finest("sqlstore.persistencemgr.registerinstancein_wkc"); // NOI18N
1184

1185            _weakCache.put(oid, sm);
1186
1187            if (sm.needsRegisterWithVersionConsistencyCache()) {
1188                addToVersionConsistencyCache(sm);
1189            }
1190        } finally {
1191            releaseCacheLock();
1192        }
1193    }
1194
1195    /**
1196     * Register instance in the transactional cache
1197     */

1198    public void registerInstance(StateManager sm, Object JavaDoc oid,
1199                boolean throwDuplicateException,
1200                boolean forceRegister) {
1201        if (oid == null) {
1202            oid = sm.getObjectId();
1203        }
1204
1205        boolean debug = logger.isLoggable();
1206        if (debug) {
1207            Object JavaDoc[] items = new Object JavaDoc[] {Thread.currentThread(), oid, sm, this, _jta};
1208            logger.finest("sqlstore.persistencemgr.registerinstance",items); // NOI18N
1209
}
1210
1211        //
1212
// register in all caches
1213
// We do explicit synchronization here using the cacheMutex. Note that for
1214
// performance reason, we only synchronize in the case where the instance
1215
// is not already in the cache.
1216
//
1217
try {
1218            acquireCacheLock();
1219            if (!_weakCache.containsKey(oid)) {
1220                if (debug)
1221                    logger.finest("sqlstore.persistencemgr.registerinstancein_wkc"); // NOI18N
1222

1223                _weakCache.put(oid, sm);
1224            } else if (throwDuplicateException) {
1225                StateManager old = (StateManager)_weakCache.get(oid);
1226                if (_supersedeDeletedInstance && old.isDeleted()) {
1227
1228                if (debug)
1229                    logger.finer(I18NHelper.getMessage(messages,
1230                        "sqlstore.persistencemgr.replacingdeletedinstance", oid)); // NOI18N
1231

1232                    old.markNotRegistered();
1233                    old.markVerifyAtDeregister();
1234                    sm.markVerifyAtDeregister();
1235                    sm.markReplacement();
1236
1237                    // Add the dependency management, so that delete happens
1238
// before the insert. This operation registers the new instance.
1239
old.addDependency(sm);
1240
1241                    // Now we need to replace the old StateManager with the new
1242
// in the _weakCache, because of the StateManager's dependency
1243
// process.
1244
_weakCache.put(oid, sm);
1245
1246                    // Do not proceed as addDependency registered instance already.
1247
return;
1248
1249                } else {
1250                    throw new JDODuplicateObjectIdException(I18NHelper.getMessage(messages,
1251                        "jdo.persistencemanagerimpl.internalmakepersistent.dups"), // NOI18N
1252
new Object JavaDoc[]{sm.getPersistent()});
1253                }
1254            }
1255
1256            if (_activeTransaction && (sm.isTransactional() || forceRegister)) {
1257                if (debug) {
1258                    Object JavaDoc[] items = new Object JavaDoc[] {oid,sm.getPersistent(),this, _jta};
1259                    logger.finest("sqlstore.persistencemgr.registerinstancein_txc",items); // NOI18N
1260
}
1261
1262                // Need to be carefull not to request registerInstance twice
1263
// for a dirty instance.
1264
if (sm.isDirty()) {
1265                    _txCache.add(sm);
1266                }
1267
1268                // _flushedCache is a Set so it cannot have duplicates.
1269
_flushedCache.add(sm);
1270
1271                if (sm.needsRegisterWithVersionConsistencyCache()) {
1272                    addToVersionConsistencyCache(sm);
1273                }
1274            }
1275
1276        } finally {
1277            releaseCacheLock();
1278        }
1279    }
1280
1281    public void deregisterInstance(Object JavaDoc oid) {
1282        boolean debug = logger.isLoggable(Logger.FINEST);
1283        if (debug) {
1284            Object JavaDoc[] items = new Object JavaDoc[] {oid,this,_jta};
1285            logger.finest("sqlstore.persistencemgr.deregisterinstance",items); // NOI18N
1286
}
1287
1288        if (oid != null) {
1289            try {
1290                acquireCacheLock();
1291                StateManager sm = (StateManager) _weakCache.remove(oid);
1292                removeFromCaches(sm);
1293            } finally {
1294                releaseCacheLock();
1295            }
1296        }
1297    }
1298
1299    public void deregisterInstance(Object JavaDoc oid, StateManager sm) {
1300        boolean debug = logger.isLoggable(Logger.FINEST);
1301        if (debug) {
1302            Object JavaDoc[] items = new Object JavaDoc[] {oid,this,_jta};
1303            logger.finest("sqlstore.persistencemgr.deregisterinstance.verify",items); // NOI18N
1304
}
1305
1306        try {
1307            acquireCacheLock();
1308            Object JavaDoc known = _weakCache.get(oid);
1309            if (known == sm) {
1310                //deregister the instance from weak cache only if it is registered.
1311
_weakCache.remove(oid);
1312                if (debug)
1313                    logger.finest("sqlstore.persistencemgr.deregisterinstance.verified"); // NOI18N
1314
}
1315
1316            removeFromCaches(sm);
1317        } finally {
1318            releaseCacheLock();
1319        }
1320    }
1321
1322    /**
1323     * If a transaction is active, removes the given StateManger from all
1324     * caches, otherwise just from the Version Consistency cache.
1325     * @param sm StateManager to remove
1326     */

1327    private void removeFromCaches(StateManager sm) {
1328        if (sm != null) {
1329            if (_activeTransaction) {
1330                // RESOLVE: Duplicates are not removed!
1331
_txCache.remove(sm);
1332                _flushedCache.remove(sm);
1333            }
1334            removeFromVersionConsistencyCache(sm);
1335        }
1336    }
1337
1338
1339    /**
1340     * Called by Transaction commit(). Flushes dirty instances to the store.
1341     * Clean instances registered for Version Consistency are verified with
1342     * the store.
1343     */

1344    public void beforeCompletion() {
1345        if (logger.isLoggable(Logger.FINEST)) {
1346            logger.finest("sqlstore.persistencemgr.beforecompletion"); // NOI18N
1347
}
1348
1349        assertIsOpen();
1350        assertActiveTransaction(false);
1351        _insideCommit = true;
1352
1353        prepareToUpdate();
1354
1355        try {
1356            flushTxCache();
1357
1358            // Verify version consistent instances on commit only.
1359
if (!_insideFlush) {
1360                verifyFlushedCache();
1361            }
1362        } catch (JDODataStoreException ex) {
1363
1364            // If an instance failed to flush, remember to cleanup the Version
1365
// Consistency cache (see afterCompletion).
1366
cleanupVersionConsistencyCache = true;
1367            throw ex;
1368        }
1369    }
1370
1371    /**
1372     * Calls the state manager's prepare to update phases I-III.
1373     * Phase II and III are called during commit processing only.
1374     *
1375     * @see StateManager#prepareToUpdatePhaseI
1376     * @see StateManager#prepareToUpdatePhaseII
1377     * @see StateManager#prepareToUpdatePhaseIII
1378     */

1379    private void prepareToUpdate() {
1380        for (int i = 0; i < _txCache.size(); i++) {
1381            StateManager sm = (StateManager)_txCache.get(i);
1382            // NOTE: prepareToUpdatePhaseI has the side-effect of adding more objects
1383
// to the transaction cache.
1384

1385            sm.prepareToUpdatePhaseI();
1386        }
1387
1388        // We only do phase 2 and 3 during commit only.
1389
if (!_insideFlush) {
1390            HashSet phase3sms = new HashSet();
1391
1392            for (Iterator iter = _flushedCache.iterator(); iter.hasNext(); ) {
1393                StateManager sm = (StateManager)iter.next();
1394                // NOTE: prepareToUpdatePhaseII has the side-effect of adding state managers
1395
// to the phase3sms HashSet which need to have prepareToUpdatePhaseIII()
1396
// called on them
1397

1398                sm.prepareToUpdatePhaseII(phase3sms);
1399            }
1400
1401            Iterator iter = phase3sms.iterator();
1402
1403            // phase3sms should contain all the non-reachable autopersistence instance.
1404
// We need to call prepareToUpdatePhaseIII on them to make sure we roll
1405
// back any changes that may have been flushed to the datastore.
1406

1407            while (iter.hasNext()) {
1408                StateManager sm = (StateManager) iter.next();
1409                sm.prepareToUpdatePhaseIII();
1410            }
1411        }
1412    }
1413
1414    /**
1415     * Writes the instances from the transactional cache to the store.
1416     * The transactional cache contains modified instances only.
1417     *
1418     * @exception JDOUserException if instances can't be flushed
1419     * because of circular dependencies.
1420     */

1421    private void flushTxCache() {
1422        List err = flushToDataStore(_txCache);
1423
1424        // Try to resolve dependencies.
1425
if (err != null && err.size() > 0) {
1426            Iterator iter = err.iterator();
1427            while (iter.hasNext()) {
1428                ((StateManager) iter.next()).resolveDependencies();
1429            }
1430            // Second flush.
1431
err = flushToDataStore(err);
1432        }
1433
1434        if (err != null && err.size() > 0) {
1435            _transaction.setRollbackOnly();
1436            throw new JDOUserException(I18NHelper.getMessage(messages,
1437                    "jdo.persistencemanagerimpl.notprocessed"), // NOI18N
1438
toPCArray(err));
1439        }
1440    }
1441
1442    /**
1443     * Loops through flushed cache and calls PersistentStore.verifyPersistent()
1444     * on each instance. The flushed cache contains all instances accessed in
1445     * this transaction. To prevent database deadlocks, it's important to
1446     * iterate the flushed cache in the order the instances were used in the
1447     * transaction, as garanteed by {@link LinkedHashSet}.
1448     *
1449     * @exception JDODataStoreException if a cached instance has been updated
1450     * from outside.
1451     */

1452    private void verifyFlushedCache() {
1453        Iterator iter = _flushedCache.iterator();
1454
1455        while (iter.hasNext()) {
1456            StateManager sm = (StateManager)iter.next();
1457
1458            if (sm.hasVersionConsistency() && !sm.verifyPersistent()) {
1459                Object JavaDoc [] items = { sm.getPersistent() };
1460
1461                // The instance failed the verification with the data store.
1462
sm.setVerificationFailed();
1463                throw new JDODataStoreException(I18NHelper.getMessage(messages,
1464                        "jdo.persistencemanagerimpl.verificationfailed"), items); // NOI18N
1465
}
1466        }
1467    }
1468
1469    /**
1470     * Writes the instances in <code>flushList</code> to the data store.
1471     * Loops through the list and calls StateManager.updatePersistent()
1472     * on each instance.
1473     *
1474     * @param flushList List of state managers to be flushed.
1475     * @return List containing state managers not flushed
1476     * because of unresolved dependencies, null if all
1477     * instances could be processed.
1478     */

1479    static private List flushToDataStore(List flushList) {
1480        int size = flushList.size();
1481        List errorList = null;
1482
1483        // The connection initialisation is not neccessary. There
1484
// are two conditions in TransactionImpl assuring connections
1485
// are not released in releaseConnections,
1486
// even if the internal reference count on the connection is 0:
1487
// - we are in the commit processing
1488
// - in a non managed environment, connections aquired for queries in pessimistic
1489
// transactions are not released until commit
1490
// Please refer to TransactionImpl.releaseConnection
1491
for (int i = 0; i < size; i++) {
1492            StateManager sm = (StateManager)flushList.get(i);
1493            StateManager smNext =
1494                (i+1 < size)? (StateManager)flushList.get(i+1) : null;
1495            sm.updatePersistent(smNext);
1496        }
1497
1498        for (int i = 0; i < size; i++) {
1499            StateManager sm = (StateManager)flushList.get(i);
1500            if (!sm.isProcessed()) {
1501                if (errorList == null) {
1502                    errorList = new ArrayList();
1503                }
1504
1505                // Dependencies have not been resolved.
1506
errorList.add(sm);
1507            }
1508        }
1509        return errorList;
1510    }
1511
1512    /**
1513     * Converts the list <code>smList</code> of state managers into
1514     * an Array of persistence capable instances.
1515     *
1516     * @param smList List of state managers.
1517     * @return Array of persistence capable instances.
1518     */

1519    static private Object JavaDoc[] toPCArray(List smList) {
1520        final int size = smList.size();
1521        if (size > 0) {
1522            List pcList = new ArrayList(size);
1523
1524            for (int i = 0; i < size; i++) {
1525                StateManager sm = (StateManager)smList.get(i);
1526                pcList.add(sm.getPersistent());
1527            }
1528            return pcList.toArray();
1529        }
1530        return null;
1531    }
1532
1533    /**
1534     * Called by Transaction commit() or rollback()
1535     * cleans up transactional cache
1536     * @param status javax.transaction.Status
1537     */

1538    public void afterCompletion(int status) {
1539        assertIsOpen();
1540        _insideCommit = true;
1541        boolean abort = ((status == Status.STATUS_ROLLEDBACK) ||
1542                (status == Status.STATUS_ROLLING_BACK) ||
1543                (status == Status.STATUS_MARKED_ROLLBACK));
1544        boolean debug = false;
1545        debug = logger.isLoggable(Logger.FINEST);
1546        if (debug)
1547            logger.finest("sqlstore.persistencemgr.aftercompletion",new Boolean JavaDoc(abort)); // NOI18N
1548

1549        boolean retainValues = _transaction.getRetainValues();
1550
1551        for (Iterator iter = _flushedCache.iterator(); iter.hasNext(); ) {
1552            StateManager sm = (StateManager)iter.next();
1553            if (debug)
1554                logger.finest("sqlstore.persistencemgr.aftercompletion.process",sm.getObjectId()); // NOI18N
1555

1556            if (abort) {
1557                rollback(sm, retainValues);
1558            } else {
1559                commit(sm, retainValues);
1560            }
1561        }
1562
1563        // Clear the transactional caches
1564
_txCache.clear();
1565        _flushedCache.clear();
1566
1567        _insideCommit = false;
1568        cleanupVersionConsistencyCache = false;
1569    }
1570
1571    /**
1572     * Commits the given StateManager instance after first adding it to the
1573     * Version Consistency cache (if necessary).
1574     * @param sm Instance to be comitted and possibly added to the cache.
1575     * @param retainValues as per the current transaction.
1576     */

1577    private void commit(StateManager sm, boolean retainValues) {
1578
1579        if (sm.needsUpdateInVersionConsistencyCache()) {
1580            StateManager nonTxSM = lookupFromVersionConsistencyCache(sm);
1581
1582            if (null != nonTxSM) {
1583                nonTxSM.copyFields(sm);
1584            } else {
1585                addToVersionConsistencyCache(sm);
1586            }
1587        }
1588        sm.commit(retainValues);
1589    }
1590
1591    /**
1592     * Does a rollback on the given StateManager instance after first removing
1593     * it from the Version Consistency cache (if necessary).
1594     * @param sm Instance to be rolled back and possibly removed from the
1595     * cache.
1596     * @param retainValues as per the current transaction.
1597     */

1598    private void rollback(StateManager sm, boolean retainValues) {
1599        if (cleanupVersionConsistencyCache && sm.isVerificationFailed()) {
1600            removeFromVersionConsistencyCache(sm);
1601        }
1602        sm.rollback(retainValues);
1603    }
1604
1605    /**
1606     * Adds given instance to the Version Consistency cache, if the
1607     * instance supports Version Consistency.
1608     * @param sm Instance to be added to the cache.
1609     * @return If an instance was already in the cache for the given
1610     * <code>sm</code>, it is returned; otherwise null.
1611     */

1612    private StateManager addToVersionConsistencyCache(StateManager sm) {
1613        StateManager rc = null;
1614
1615        if (null != sm && sm.hasVersionConsistency()) {
1616            Class JavaDoc pcType = sm.getPersistent().getClass();
1617            Object JavaDoc oid = sm.getObjectId();
1618            VersionConsistencyCache vcCache =
1619                    persistenceManagerFactory.getVersionConsistencyCache();
1620
1621            if (vcCache.get(pcType, oid) == null) {
1622                StateManager nonTxSM = createStateManager(pcType);
1623
1624                nonTxSM.copyFields(sm);
1625                nonTxSM.setPersistenceManager(null); // Disconnect SM from PM
1626

1627                rc = vcCache.put(pcType, oid, nonTxSM);
1628            }
1629        }
1630        return rc;
1631    }
1632
1633    /**
1634     * Removes given instance from the Version Consistency cache, if the
1635     * instance supports Version Consistency.
1636     * @param sm Instance to be removed from the cache.
1637     * @return If an instance was already in the cache for the given
1638     * <code>sm</code>, it is returned; otherwise null.
1639     */

1640    private StateManager removeFromVersionConsistencyCache(StateManager sm) {
1641        StateManager rc = null;
1642
1643        if (null != sm && sm.hasVersionConsistency()) {
1644            Class JavaDoc pcType = sm.getPersistent().getClass();
1645            Object JavaDoc oid = sm.getObjectId();
1646            VersionConsistencyCache vcCache =
1647                    persistenceManagerFactory.getVersionConsistencyCache();
1648            rc = vcCache.remove(pcType, oid);
1649
1650            if (null == rc) {
1651                // XXX should not happen; throw exception?
1652
}
1653        }
1654        return rc;
1655    }
1656
1657    /**
1658     * @inheritDoc
1659     */

1660    public boolean initializeFromVersionConsistencyCache(StateManager sm) {
1661        boolean rc = false;
1662        StateManager nonTxSM = lookupFromVersionConsistencyCache(sm);
1663
1664        if (null != nonTxSM) {
1665            rc = true;
1666
1667            // Synchronize so that no other threads change/access the
1668
// cache'd nonTxSm while copying fields.
1669
synchronized (nonTxSM) {
1670                sm.copyFields(nonTxSM);
1671            }
1672            sm.initialize(true);
1673        }
1674        return rc;
1675    }
1676
1677    /**
1678     * Looks up given instance from the Version Consistency cache, if the
1679     * instance supports Version Consistency.
1680     * @param sm Instance to be looked up from the cache.
1681     * @return If an instance was already in the cache for the given
1682     * <code>sm</code>, it is returned; otherwise null.
1683     */

1684    private StateManager lookupFromVersionConsistencyCache(StateManager sm) {
1685        StateManager rc = null;
1686
1687        if (null != sm && sm.hasVersionConsistency()) {
1688            Class JavaDoc pcType = sm.getPersistent().getClass();
1689            Object JavaDoc oid = sm.getObjectId();
1690            VersionConsistencyCache vcCache =
1691                persistenceManagerFactory.getVersionConsistencyCache();
1692
1693            rc = vcCache.get(pcType, oid);
1694        }
1695        return rc;
1696    }
1697
1698    public void setStateManager(Object JavaDoc pc, StateManager sm) {
1699        if (pc instanceof PersistenceCapable) {
1700            ((PersistenceCapable) pc).jdoSetStateManager(sm);
1701        }
1702
1703        //RESOLVE: Otherwise, should throw an exception.
1704
}
1705
1706
1707    public void setFlags(Object JavaDoc pc, byte flags) {
1708        if (pc instanceof PersistenceCapable) {
1709            ((PersistenceCapable) pc).jdoSetFlags(flags);
1710        }
1711
1712        //RESOLVE: Otherwise, should throw an exception.
1713
}
1714
1715    public byte getFlags(Object JavaDoc pc) {
1716        if (pc instanceof PersistenceCapable) {
1717            return ((PersistenceCapable) pc).jdoGetFlags();
1718        }
1719
1720        return 0;
1721        //RESOLVE: Otherwise, should throw an exception.
1722
}
1723
1724    public StateManager getStateManager(Object JavaDoc pc) {
1725        if (pc instanceof PersistenceCapable) {
1726            return ((PersistenceCapable) pc).jdoGetStateManager();
1727        }
1728
1729        return null;
1730        //RESOLVE: Otherwise, should throw an exception.
1731
}
1732
1733
1734    public void setField(Object JavaDoc o, int fieldNumber, Object JavaDoc value) {
1735        if (o instanceof PersistenceCapable) {
1736            PersistenceCapable pc = (PersistenceCapable) o;
1737            pc.jdoSetField(fieldNumber, value);
1738        }
1739
1740        //RESOLVE: Otherwise, should throw an exception.
1741
}
1742
1743    public Object JavaDoc getField(Object JavaDoc pc, int fieldNumber) {
1744        if (pc instanceof PersistenceCapable) {
1745            return ((PersistenceCapable) pc).jdoGetField(fieldNumber);
1746        }
1747
1748        //RESOLVE: Otherwise, should throw an exception.
1749
return null;
1750    }
1751
1752    public void clearFields(Object JavaDoc pc) {
1753        if (pc instanceof PersistenceCapable) {
1754            ((PersistenceCapable) pc).jdoClear();
1755        }
1756    }
1757
1758    /**
1759     * Returns a new Second Class Object instance of the type specified,
1760     * with the owner and field name to notify upon changes to the value
1761     * of any of its fields. If a collection class is created, then the
1762     * class does not restrict the element types, and allows nulls to be added as elements.
1763     *
1764     * @param type Class of the new SCO instance
1765     * @param owner the owner to notify upon changes
1766     * @param fieldName the field to notify upon changes
1767     * @return the object of the class type
1768     */

1769    public Object JavaDoc newSCOInstance(Class JavaDoc type, Object JavaDoc owner, String JavaDoc fieldName) {
1770        Object JavaDoc obj = null;
1771
1772        if (Collection.class.isAssignableFrom(type)) {
1773            obj = this.newCollectionInstanceInternal(type, owner, fieldName, null, true, 0);
1774        } else {
1775            obj = newSCOInstanceInternal(type, owner, fieldName);
1776
1777        }
1778
1779        this.replaceSCO(fieldName, owner, obj);
1780
1781
1782        return obj;
1783    }
1784
1785    /**
1786     * Called by newSCOInstance from the public interface or internally
1787     * by the runtime
1788     * Will not result in marking field as dirty
1789     *
1790     * Returns a new Second Class Object instance of the type specified,
1791     * @param type Class of the new SCO instance
1792     * @param owner the owner to notify upon changes
1793     * @param fieldName the field to notify upon changes
1794     * @return the object of the class type
1795     */

1796    public Object JavaDoc newSCOInstanceInternal(Class JavaDoc type, Object JavaDoc owner, String JavaDoc fieldName) {
1797
1798        Object JavaDoc obj = null;
1799
1800        if (type == java.sql.Date JavaDoc.class
1801                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlDate.class) {
1802            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlDate(owner, fieldName);
1803
1804        } else if (type == java.sql.Time JavaDoc.class
1805                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTime.class) {
1806            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTime(owner, fieldName);
1807
1808        } else if (type == java.sql.Timestamp JavaDoc.class
1809                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTimestamp.class) {
1810            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTimestamp(owner, fieldName);
1811
1812        } else if (type == com.sun.jdo.spi.persistence.support.sqlstore.sco.Date.class
1813                || Date.class.isAssignableFrom(type)) {
1814            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.Date(owner, fieldName);
1815
1816        } else {
1817            throw new JDOUserException(I18NHelper.getMessage(messages,
1818                    "jdo.persistencemanagerimpl.newscoinstance.wrongclass", // NOI18N
1819
type.getName()));
1820        }
1821
1822        return obj;
1823    }
1824
1825
1826    /**
1827     * Returns a new Collection instance of the type specified, with the
1828     * owner and field name to notify upon changes to the value of any of its fields.
1829     * The collection class restricts the element types allowed to the elementType or
1830     * instances assignable to the elementType, and allows nulls to be added as
1831     * elements based on the setting of allowNulls. The Collection has an initial size
1832     * as specified by the initialSize parameter.
1833     * We choose to use HashSet as a default collection (no specific type is chosen)
1834     * because we do not support duplicate objects in DB
1835     *
1836     * @param type Class of the new SCO instance
1837     * @param owner the owner to notify upon changes
1838     * @param fieldName the field to notify upon changes
1839     * @param elementType the element types allowed
1840     * @param allowNulls true if allowed
1841     * @param initialSize initial size of the Collection
1842     * @return the object of the class type
1843     */

1844    public Object JavaDoc newCollectionInstance(Class JavaDoc type, Object JavaDoc owner, String JavaDoc fieldName,
1845                                        Class JavaDoc elementType, boolean allowNulls, int initialSize) {
1846        Object JavaDoc obj = newCollectionInstanceInternal(type, owner, fieldName,
1847                elementType, allowNulls, initialSize);
1848
1849        this.replaceSCO(fieldName, owner, obj);
1850
1851        return obj;
1852    }
1853
1854    /**
1855     * Called by newCollectionInstance from the public interface or internally
1856     * by the runtime
1857     * Will not result in marking field as dirty
1858     *
1859     * @see #newCollectionInstance for more information
1860     * @param type Class of the new SCO instance
1861     * @param owner the owner to notify upon changes
1862     * @param fieldName the field to notify upon changes
1863     * @param elementType the element types allowed
1864     * @param allowNulls true if allowed
1865     * @param initialSize initial size of the Collection
1866     * @return the object of the class type
1867     */

1868    public Object JavaDoc newCollectionInstanceInternal(Class JavaDoc type, Object JavaDoc owner, String JavaDoc fieldName,
1869                                                Class JavaDoc elementType, boolean allowNulls, int initialSize) {
1870        Object JavaDoc obj = null;
1871
1872        // Make sure that the order of type comparison will go from
1873
// narrow to wide:
1874
if (type == HashSet.class
1875                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet.class) {
1876            if (initialSize == 0)
1877                initialSize = 101;
1878            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet(
1879                owner, fieldName, elementType, allowNulls, initialSize);
1880/*
1881        } else if (type == Vector.class
1882                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.Vector.class) {
1883            newType = com.sun.jdo.spi.persistence.support.sqlstore.sco.Vector.class;
1884        } else if (type == ArrayList.class
1885                || type == com.sun.jdo.spi.persistence.support.sqlstore.sco.ArrayList.class) {
1886            newType = com.sun.jdo.spi.persistence.support.sqlstore.sco.ArrayList.class;
1887        } else if (List.class.isAssignableFrom(type)) {
1888            newType = com.sun.jdo.spi.persistence.support.sqlstore.sco.Vector.class;
1889*/

1890        } else if (Set.class.isAssignableFrom(type)) {
1891            if (initialSize == 0)
1892                initialSize = 101;
1893            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet(
1894                owner, fieldName, elementType, allowNulls, initialSize);
1895
1896        } else if (Collection.class.isAssignableFrom(type)) {
1897            // We choose to use HashSet as a default collection
1898
// because we do not support duplicate objects in DB
1899
if (initialSize == 0)
1900                initialSize = 101;
1901            obj = new com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet(
1902                owner, fieldName, elementType, allowNulls, initialSize);
1903
1904        } else {
1905            throw new JDOUserException(I18NHelper.getMessage(messages,
1906                    "jdo.persistencemanagerimpl.newscoinstance.wrongclass", // NOI18N
1907
type.getName()));
1908        }
1909        boolean debug = logger.isLoggable(Logger.FINEST);
1910        if (debug)
1911            logger.finest("sqlstore.persistencemgr.newcollection",obj.getClass()); // NOI18N
1912

1913        return obj;
1914    }
1915
1916    /**
1917     * Called by Query to flush updates to the database
1918     * in pessimistic transaction. Calls internaly beforeCompletion() to do actual
1919     * flush
1920     * @see #beforeCompletion()
1921     */

1922    public void internalFlush() {
1923        acquireExclusiveLock();
1924
1925        try {
1926            //
1927
// Only flush if we are not in optimistic transaction.
1928
//
1929
if (_optimistic == false) {
1930                //
1931
// Note: no need to lock _cacheLock because we already have
1932
// exclusive using of the _weakCache and _txCache due to
1933
// the exclusive lock.
1934
//
1935

1936                _insideFlush = true;
1937                beforeCompletion();
1938                _insideCommit = false;
1939
1940                int status = _transaction.getStatus();
1941
1942                if ((status == Status.STATUS_ROLLEDBACK) ||
1943                        (status == Status.STATUS_ROLLING_BACK) ||
1944                        (status == Status.STATUS_MARKED_ROLLBACK)) {
1945                    return; // it is user's responsibility to rollback the transaction
1946
//_transaction.rollback();
1947
} else {
1948                    for (int i = 0; i < _txCache.size(); i++) {
1949                        StateManager sm = (StateManager)_txCache.get(i);
1950                        sm.flushed();
1951                    }
1952                }
1953                _insideFlush = false;
1954
1955                // Clear the dirty cache
1956
_txCache.clear();
1957            }
1958        } finally {
1959            releaseExclusiveLock();
1960        }
1961    }
1962
1963    /**
1964     * For Transaction to notify PersistenceManager that
1965     * status is changed
1966     */

1967    public synchronized void notifyStatusChange(boolean isActive) {
1968        _activeTransaction = isActive;
1969    }
1970
1971    /**
1972     * For Transaction to notify PersistenceManager that
1973     * optimistic flag is changed
1974     */

1975    public synchronized void notifyOptimistic(boolean optimistic) {
1976        this._optimistic = optimistic;
1977    }
1978
1979    /**
1980     * Returns true if associated transaction is optimistic
1981     */

1982    public boolean isOptimisticTransaction() {
1983        boolean debug = logger.isLoggable(Logger.FINEST);
1984        if (debug)
1985            logger.finest("sqlstore.persistencemgr.isoptimistic", new Boolean JavaDoc(_optimistic)); // NOI18N
1986

1987        return _optimistic;
1988    }
1989
1990
1991    /**
1992     * For Transaction to notify PersistenceManager that
1993     * nontransactionalRead flag is changed
1994     */

1995    public synchronized void notifyNontransactionalRead(boolean nontransactionalRead) {
1996        this._nontransactionalRead = nontransactionalRead;
1997    }
1998
1999    /**
2000     * Returns true if associated transaction is optimistic
2001     */

2002    public boolean isNontransactionalRead() {
2003        boolean debug = logger.isLoggable(Logger.FINEST);
2004        if (debug) {
2005            logger.finest("sqlstore.persistencemgr.isnontxread",new Boolean JavaDoc(_nontransactionalRead)); // NOI18N
2006
}
2007
2008        return _nontransactionalRead;
2009    }
2010
2011
2012    /**
2013     * Returns true if associated transaction is active
2014     */

2015    public boolean isActiveTransaction() {
2016        boolean debug = logger.isLoggable(Logger.FINEST);
2017        if (debug)
2018             logger.finest("sqlstore.persistencemgr.isactivetx",new Boolean JavaDoc(_activeTransaction)); // NOI18N
2019

2020        return _activeTransaction;
2021    }
2022
2023    // Returns current wrapper
2024
public PersistenceManagerWrapper getCurrentWrapper() {
2025        boolean debug = logger.isLoggable(Logger.FINEST);
2026        if (debug) {
2027            logger.finest("sqlstore.persistencemgr.getcurrentwrapper",current); // NOI18N
2028
}
2029
2030        return current;
2031    }
2032
2033
2034
2035
2036
2037    // Remember the current wrapper
2038
protected void pushCurrentWrapper(PersistenceManagerWrapper pmw) {
2039        boolean debug = logger.isLoggable(Logger.FINEST);
2040        if (debug) {
2041            Object JavaDoc[] items = new Object JavaDoc[] {current,pmw};
2042            logger.finest("sqlstore.persistencemgr.pushcurrentwrapper",items); // NOI18N
2043
}
2044
2045        current = pmw;
2046    }
2047
2048    // Replace current wrapper with the previous
2049
protected void popCurrentWrapper(PersistenceManagerWrapper prev) {
2050        boolean debug = logger.isLoggable(Logger.FINEST);
2051        if (debug) {
2052            Object JavaDoc[] items = new Object JavaDoc[] {current,prev};
2053            logger.finest("sqlstore.persistencemgr.popcurrentwrapper",items); // NOI18N
2054
}
2055
2056        current = prev;
2057        if (!_isClosed && _jta == null && current == null) {
2058            this.close();
2059        }
2060    }
2061
2062    /**
2063     * Assigns reference to javax.transaction.Transaction associated
2064     * with the current thread in the managed environment
2065     */

2066    protected void setJTATransaction(javax.transaction.Transaction JavaDoc t) {
2067        if (this._jta != null) {
2068            Object JavaDoc[] items = new Object JavaDoc[] {this._jta, t};
2069            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
2070                    "jdo.persistencemanagerimpl.setjtatransaction.notnulljta", // NOI18N
2071
items));
2072        }
2073        this._jta = t;
2074    }
2075
2076    /** Add a new created query instance to the queries collection. */
2077    private void registerQuery(QueryImpl q)
2078    {
2079        acquireExclusiveLock();
2080
2081        try {
2082            queries.add(q);
2083        } finally {
2084            releaseExclusiveLock();
2085        }
2086    }
2087
2088    /**
2089     * Disconnects all query instances created for this pm and nullifies the
2090     * collection. This is to allow this pm to be gargabe collected.
2091     */

2092    private void disconnectQueries()
2093    {
2094        for (Iterator i = queries.iterator(); i.hasNext();)
2095        {
2096            QueryImpl q = (QueryImpl)i.next();
2097            q.clearPersistenceManager();
2098        }
2099        queries.clear();
2100        queries = null;
2101    }
2102
2103    /** --------------Private Methods-------------- */
2104
2105    /**
2106     * Replace previous value of the SCO field with the newly created
2107     *
2108     * @param fieldName the field to notify upon changes
2109     * @param owner the owner to notify upon changes
2110     * @param obj new SCO Instance
2111     */

2112    private void replaceSCO(String JavaDoc fieldName, Object JavaDoc owner, Object JavaDoc obj) {
2113        if (owner instanceof PersistenceCapable) {
2114            acquireShareLock();
2115
2116            try {
2117                // Assign this SCO Collection to owner as reference
2118
PersistenceCapable pc = (PersistenceCapable) owner;
2119                StateManager sm = pc.jdoGetStateManager();
2120
2121                if (obj instanceof SCOCollection) {
2122                    acquireFieldUpdateLock();
2123                    try {
2124                        sm.replaceObjectField(fieldName, obj);
2125                    } finally {
2126                        releaseFieldUpdateLock();
2127                    }
2128                } else {
2129                    sm.replaceObjectField(fieldName, obj);
2130                }
2131            } finally {
2132                releaseShareLock();
2133            }
2134        }
2135    }
2136
2137    private Object JavaDoc internalGetObjectId(StateManager sm) {
2138        Object JavaDoc oid = sm.getObjectId();
2139
2140        // create a copy
2141
return internalCloneOid(oid, sm);
2142    }
2143
2144    private void internalMakePersistent(PersistenceCapable pc) {
2145        //
2146
// We need to lock _fieldUpdateLock here because of
2147
// the persitence-by-reacheability algorithm that can
2148
// touch other instances.
2149
// RESOLVE: We can optimize here to not have to lock
2150
// _fieldUpdateLock if the instance does not contain any
2151
// relationship field.
2152
//
2153
acquireFieldUpdateLock();
2154        try {
2155            synchronized (pc) {
2156                StateManager sm = null;
2157
2158                if (pc.jdoIsPersistent()) {
2159                    sm = pc.jdoGetStateManager();
2160
2161                    if (this != pc.jdoGetStateManager().getPersistenceManagerInternal()) {
2162                        throw new JDOUserException(I18NHelper.getMessage(messages,
2163                                "jdo.persistencemanagerimpl.another_pm"), // NOI18N
2164
new Object JavaDoc[]{pc});
2165                    }
2166                } else {
2167                    Class JavaDoc classType = pc.getClass();
2168                    loadPersistenceConfig(classType);
2169                    sm = _store.getStateManager(classType);
2170                }
2171
2172                sm.makePersistent(this, pc);
2173            }
2174        } finally {
2175            releaseFieldUpdateLock();
2176        }
2177    }
2178
2179    private void internalDeletePersistent(PersistenceCapable pc) {
2180        if (!(pc.jdoIsPersistent())) {
2181            throw new JDOException(I18NHelper.getMessage(messages,
2182                    "jdo.persistencemanagerimpl.internaldeletepersistent.transient"), // NOI18N
2183
new Object JavaDoc[]{pc});
2184        }
2185
2186        StateManager sm = pc.jdoGetStateManager();
2187        PersistenceManager pm = (PersistenceManager) sm.getPersistenceManagerInternal();
2188
2189        if (this != pm) {
2190            throw new JDOUserException(I18NHelper.getMessage(messages,
2191                    "jdo.persistencemanagerimpl.another_pm"), // NOI18N
2192
new Object JavaDoc[]{pc});
2193        }
2194
2195        if (!pc.jdoIsDeleted()) {
2196            //
2197
// Synchronization is done in the state manager.
2198
//
2199
sm.deletePersistent();
2200        }
2201    }
2202
2203    /**
2204     * Load metadata for the given OID Object
2205     * @param oid the Oid
2206     * @return classtype for the owning Class
2207     */

2208    private Class JavaDoc loadClassForOid(Object JavaDoc oid) {
2209        Class JavaDoc oidClass = oid.getClass();
2210        Class JavaDoc classType = _store.getClassByOidClass(oidClass);
2211        if (classType != null) {
2212            // Found in the DataStore
2213
return classType;
2214        }
2215
2216        // loadDirectory(oidClass.getName());
2217
// loadClassByMethod(oid, oidClass);
2218
loadByName(oidClass.getName(), oidClass.getClassLoader());
2219
2220        return _store.getClassByOidClass(oidClass);
2221    }
2222
2223    /**
2224     * Load meta data for Object Class from package info
2225     *
2226     * @param s OID class name as String
2227     * @param classLoader the classLoader of the oid class
2228     */

2229    private void loadByName(String JavaDoc s, ClassLoader JavaDoc classLoader) {
2230        int l = s.length();
2231
2232        if (l < 4) {
2233            // Does not fit the pattern
2234
return;
2235        }
2236
2237        String JavaDoc s1 = s.substring(l - 3);
2238
2239        if (s1.equalsIgnoreCase(oidName_OID) &&
2240                (s.charAt(l - 4) == '.' || s.charAt(l - 4) == '$')) {
2241            s = s.substring(0, l - 4);
2242        } else if (s1.equalsIgnoreCase(oidName_KEY)) {
2243            s = s.substring(0, l - 3);
2244        } else {
2245            return;
2246        }
2247
2248        boolean debug = logger.isLoggable(Logger.FINEST);
2249        if (debug)
2250            logger.finest("sqlstore.persistencemgr.loadingclass",s); // NOI18N
2251

2252
2253        Class JavaDoc oidClass = null;
2254
2255        try {
2256            // take current class loader if not specified
2257
if (classLoader == null) {
2258                classLoader = getClass().getClassLoader();
2259            }
2260            oidClass = Class.forName(s, true, classLoader);
2261
2262        } catch (Exception JavaDoc e) {
2263            throw new JDOFatalUserException(I18NHelper.getMessage(messages,
2264                    "jdo.persistencemanagerimpl.loadclassforoid.wrongoidclass"), e);// NOI18N
2265
}
2266
2267        loadPersistenceConfig(oidClass);
2268    }
2269
2270    /**
2271     * assert this PM instance is open
2272     */

2273    private void assertIsOpen() {
2274        if (_isClosed) {
2275            boolean debug = logger.isLoggable(Logger.FINEST);
2276            if (debug) {
2277                logger.finest("sqlstore.persistencemgr.assertisopen",this); // NOI18N
2278
}
2279            throw new JDOFatalUserException(I18NHelper.getMessage(messages,
2280                    "jdo.persistencemanagerimpl.assertclosed.closed"));// NOI18N
2281
}
2282    }
2283
2284    /**
2285     * assert that the associated Transaction is active but allows to do commit processing.
2286     */

2287    private void assertActiveTransaction(boolean insideQuery) {
2288        boolean debug = false;
2289
2290        debug = logger.isLoggable(Logger.FINEST);
2291
2292        if (debug) {
2293            logger.finest("sqlstore.persistencemgr.assertactivetx",_transaction); // NOI18N
2294
}
2295
2296        if (_insideCommit || (insideQuery && _transaction.getNontransactionalRead()))
2297            return;
2298
2299        if (!_activeTransaction) {
2300            if (debug) {
2301                logger.finest("sqlstore.persistencemgr.assertactivetx.closed",this); // NOI18N
2302
}
2303            throw new JDOException(I18NHelper.getMessage(messages,
2304                    "jdo.persistencemanagerimpl.assertactivetransaction.error"));// NOI18N
2305
}
2306    }
2307
2308    /**
2309     * assert Object is PersistenceCapable
2310     */

2311    private void assertPersistenceCapable(Object JavaDoc pc) {
2312        if (!(pc instanceof PersistenceCapable)) {
2313            throw new JDOException(I18NHelper.getMessage(messages,
2314                    "jdo.persistencemanagerimpl.assertpersistencecapable.error", // NOI18N
2315
pc.getClass().getName()), new Object JavaDoc[]{pc});
2316        }
2317    }
2318
2319    /**
2320     * Set key field values from Oid into the Object
2321     *
2322     * @param sm StateManager of the Object to set key field values to
2323     */

2324    private void setKeyFields(StateManager sm) {
2325        Object JavaDoc o = sm.getPersistent();
2326        if (o == null)
2327            return;
2328
2329        Object JavaDoc oid = sm.getObjectId();
2330        try {
2331            // Set key field vaues and mark them as present
2332
PersistenceConfig config = sm.getPersistenceConfig();
2333            Field JavaDoc keyFields[] = config.getKeyFields();
2334            String JavaDoc keynames[] = config.getKeyFieldNames();
2335            for (int i = 0; i < keyFields.length; i++) {
2336                Field JavaDoc keyField = keyFields[i];
2337                sm.makePresent(keynames[i], keyField.get(oid));
2338            }
2339
2340        } catch (Exception JavaDoc e) {
2341            //e.printStackTrace();
2342
boolean debug = logger.isLoggable(Logger.FINEST);
2343            if (debug)
2344                logger.finest("sqlstore.persistencemgr.setkeyfields",e); // NOI18N
2345
}
2346    }
2347
2348    private PersistenceConfig loadPersistenceConfig(Class JavaDoc classType) {
2349        return _store.getPersistenceConfig(classType);
2350    }
2351
2352    /**
2353     * Creates local copy of an oid object
2354     * @param oid original object
2355     * @param sm StateManager to be used for the field info.
2356     * @return object local copy
2357     */

2358    private Object JavaDoc internalCloneOid(Object JavaDoc oid, StateManager sm) {
2359        if (oid == null)
2360            return null;
2361
2362        if (!_requireCopyObjectId) {
2363            return oid;
2364        }
2365
2366        boolean debug = logger.isLoggable(Logger.FINEST);
2367
2368        Object JavaDoc newoid = null;
2369        try {
2370            Class JavaDoc oidClass = oid.getClass();
2371            newoid = oidClass.newInstance();
2372            PersistenceConfig config = sm.getPersistenceConfig();
2373            Field JavaDoc keyFields[] = config.getKeyFields();
2374
2375            // Copy key field vaues
2376
for (int i = 0; i < keyFields.length; i++) {
2377                Field JavaDoc keyField = keyFields[i];
2378                keyField.set(newoid, keyField.get(oid));
2379            }
2380
2381        } catch (Exception JavaDoc e) {
2382            //e.printStackTrace();
2383
if (debug)
2384                logger.finest("sqlstore.persistencemgr.internalcloneoid",e); // NOI18N
2385
newoid = null;
2386        }
2387
2388        if (debug)
2389            {
2390            Object JavaDoc[] items = new Object JavaDoc[] {oid , newoid, new Boolean JavaDoc((oid == newoid))};
2391            logger.finest("sqlstore.persistencemgr.internalcloneoid.old",items); // NOI18N
2392
}
2393
2394        return newoid;
2395    }
2396
2397
2398    /**
2399     * Acquires a share lock from the persistence manager. This method will
2400     * put the calling thread to sleep if another thread is holding the exclusive lock.
2401     */

2402    public void acquireShareLock() {
2403        if ( ! _multithreaded) {
2404            return;
2405        }
2406
2407        boolean debug = logger.isLoggable(Logger.FINEST);
2408
2409        synchronized (_readWriteLock) {
2410            //
2411
// If the current thread is already holding the exclusive lock,
2412
// we simply grant the share lock without incrementing
2413
// the counter.
2414
//
2415
if ((_readWriteCount < 0) &&
2416                    (_exclusiveLockHolder == Thread.currentThread())) {
2417                return;
2418            }
2419
2420            //
2421
// If _readWriteCount is negative, it means a thread is holding the exclusive lock.
2422
// We simply put this thread to sleep and wait for it to be notified by the
2423
// thread releasing the exclusive lock.
2424
//
2425
while (_readWriteCount < 0) {
2426                _waiterCount++;
2427
2428                try {
2429                    if (debug) {
2430                        logger.finest("sqlstore.persistencemgr.acquiresharedlock",Thread.currentThread()); // NOI18N
2431
}
2432
2433                    _readWriteLock.wait();
2434                } catch (InterruptedException JavaDoc e) {
2435                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
2436                            "jdo.persistencemanagerimpl.acquiresharelock.interrupted"), e);// NOI18N
2437
} finally {
2438                    _waiterCount--;
2439                }
2440            }
2441
2442            try {
2443                //
2444
// Make sure no one has closed the pm.
2445
//
2446
assertIsOpen();
2447
2448            } catch (JDOException ex) {
2449                //
2450
// If _readWriteCount is 0, it means that no thread is holding a share
2451
// or exclusive lock. If there is a thread waiting, we wake it up by
2452
// notifying it.
2453
//
2454
if (_readWriteCount == 0 && _waiterCount > 0) {
2455                    _readWriteLock.notify();
2456                }
2457                throw ex;
2458           }
2459
2460            _readWriteCount++;
2461            if (debug) {
2462              logger.finest("sqlstore.persistencemgr.acquiresharedlock.rdwrcount", // NOI18N
2463
Thread.currentThread(),new Long JavaDoc(_readWriteCount));
2464            }
2465
2466            if (_readWriteCount <= 0) {
2467                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
2468                        "jdo.persistencemanagerimpl.acquiresharelock.failed"));// NOI18N
2469
}
2470        }
2471    }
2472
2473    /**
2474     * Releases the share lock and notify any thread waiting to get an exclusive lock.
2475     * Note that every releaseShareLock() call needs to be preceeded by an acquireShareLock() call.
2476     */

2477    public void releaseShareLock() {
2478        if ( ! _multithreaded) {
2479            return;
2480        }
2481
2482        boolean debug = logger.isLoggable(Logger.FINEST);
2483
2484
2485        synchronized (_readWriteLock) {
2486            //
2487
// If the current thread is already holding the exclusive lock,
2488
// we simply release the share lock without decrementing
2489
// the counter.
2490
//
2491
if ((_readWriteCount < 0) &&
2492                    (_exclusiveLockHolder == Thread.currentThread())) {
2493                return;
2494            }
2495
2496            try {
2497                if (_readWriteCount == 0) {
2498                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
2499                            "jdo.persistencemanagerimpl.releasesharelock.failed"));// NOI18N
2500
}
2501
2502                _readWriteCount--;
2503            } finally {
2504                //
2505
// If _readWriteCount is 0, it means that no thread is holding a share
2506
// or exclusive lock. If there is a thread waiting, we wake it up by
2507
// notifying it.
2508
//
2509
if ((_waiterCount > 0) && (_readWriteCount == 0)) {
2510                    _readWriteLock.notify();
2511                }
2512
2513                if (debug) {
2514                    Object JavaDoc[] items = new Object JavaDoc[] {Thread.currentThread(),new Long JavaDoc(_readWriteCount)};
2515                    logger.finest("sqlstore.persistencemgr.releasesharedlock",items); // NOI18N
2516
}
2517            }
2518        }
2519    }
2520
2521    /**
2522     * Acquires an exclusive lock from the persistence manager. By acquiring an
2523     * exclusive lock, a thread is guaranteed to have exclusive right to the persistence
2524     * runtime meaning no other threads can perform any operation in the sqlstore.
2525     * NOTE: This implementation does not detect if a thread holding a share lock
2526     * attempts to acquire an exclusive lock. It is up to the callers to make sure
2527     * this does not happen.
2528     */

2529    public void acquireExclusiveLock() {
2530        if ( ! _multithreaded) {
2531            return;
2532        }
2533
2534        boolean debug = logger.isLoggable(Logger.FINEST);
2535
2536        synchronized (_readWriteLock) {
2537            Thread JavaDoc currentThread = Thread.currentThread();
2538
2539            //
2540
// If the current thread already holds the exclusive lock, we simply
2541
// decrement _readWriteCount to indicate the current level of the exclusive
2542
// lock.
2543
//
2544
if (currentThread == _exclusiveLockHolder) {
2545                _readWriteCount--;
2546            } else {
2547                //
2548
// If _readWriteCount is not 0, it means that there is either a share lock
2549
// or an exclusive outstanding. We simply put the current thread to sleep
2550
// any wait for it to be notified by the thread releasing the lock.
2551
//
2552
while (_readWriteCount != 0) {
2553                    _waiterCount++;
2554
2555                    try {
2556
2557                        if (debug) {
2558                             logger.finest("sqlstore.persistencemgr.acquireexclusivelock",currentThread); // NOI18N
2559
}
2560
2561                        _readWriteLock.wait();
2562                    } catch (InterruptedException JavaDoc e) {
2563                        throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
2564                                "jdo.persistencemanagerimpl.acquireexclusivelock.interrupted"), e);// NOI18N
2565
} finally {
2566                        _waiterCount--;
2567                    }
2568                }
2569
2570                try {
2571                    //
2572
// Make sure no one has closed the pm.
2573
//
2574
assertIsOpen();
2575
2576                } catch (JDOException ex) {
2577                    //
2578
// If _readWriteCount is 0 and _waiterCount is greater than 0,
2579
// we need to notify a thread waiting to acquire a lock.
2580
//
2581
if (_readWriteCount == 0 && _waiterCount > 0) {
2582                        _readWriteLock.notify();
2583                    }
2584                    throw ex;
2585               }
2586
2587                _readWriteCount = -1;
2588                _exclusiveLockHolder = currentThread;
2589
2590                if (debug) {
2591                    Object JavaDoc[] items = new Object JavaDoc[] {currentThread,new Long JavaDoc(_readWriteCount)};
2592                    logger.fine("sqlstore.persistencemgr.acquireexclusivelock.count",items); // NOI18N
2593
}
2594
2595            }
2596        }
2597    }
2598
2599    /**
2600     * Release the exclusive lock and notify any thread waiting to get an exclusive or
2601     * share lock. Note that every releaseShareLock() call needs to be preceeded by
2602     * an acquireExclusiveLock() call.
2603     */

2604    public void releaseExclusiveLock() {
2605        if ( ! _multithreaded) {
2606            return;
2607        }
2608
2609        boolean debug = logger.isLoggable(Logger.FINEST);
2610
2611
2612        synchronized (_readWriteLock) {
2613            try {
2614                if (_readWriteCount >= 0) {
2615                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
2616                            "jdo.persistencemanagerimpl.releaseexclusivelock.failed"));// NOI18N
2617
}
2618
2619                _readWriteCount++;
2620            } finally {
2621                if (debug) {
2622                    Object JavaDoc[] items = new Object JavaDoc[] {Thread.currentThread(),new Long JavaDoc(_readWriteCount)};
2623                    logger.finest("sqlstore.persistencemgr.releaseexclusivelock",items); // NOI18N
2624
}
2625
2626                //
2627
// If _readWriteCount is 0 and _waiterCount is greater than 0,
2628
// we need to notify a thread waiting to acquire a lock.
2629
//
2630
if (_readWriteCount == 0) {
2631                    if (_waiterCount > 0) {
2632                        _readWriteLock.notify();
2633                    }
2634
2635                    _exclusiveLockHolder = null;
2636                }
2637            }
2638        }
2639    }
2640
2641    /**
2642     * Acquire lock for synchronizing field updates.
2643     */

2644    public void acquireFieldUpdateLock() {
2645        _fieldUpdateLock.acquire();
2646    }
2647
2648    /**
2649     * Release lock for synchronizing field updates.
2650     */

2651    public void releaseFieldUpdateLock() {
2652        _fieldUpdateLock.release();
2653    }
2654
2655    /**
2656     * Lock cache for getObjectById and result processing synchronization.
2657     */

2658    public void acquireCacheLock() {
2659        _cacheLock.acquire();
2660    }
2661
2662    /** Release cache lock.
2663     */

2664    public void releaseCacheLock() {
2665        _cacheLock.release();
2666    }
2667
2668    /** --------------Inner Class-------------- */
2669
2670    /**
2671     * Class that implements interface FilenameFilter.
2672     * Used to filter directory listings in the list method of class File.
2673     */

2674    static class ExtensionFilter implements FilenameFilter JavaDoc {
2675        private String JavaDoc ext;
2676
2677        public ExtensionFilter(String JavaDoc ext) {
2678            this.ext = ext;
2679        }
2680
2681        /**
2682         * Tests if a specified file should be included in a file list.
2683         * @param dir the directory in which the file was found
2684         * @param name the name of the file
2685         * @return true if the name should be included in the file list
2686         */

2687        public boolean accept(File JavaDoc dir, String JavaDoc name) {
2688            return name.endsWith(ext);
2689        }
2690    }
2691
2692}
2693
Popular Tags