/**
* Speedo: an implementation of JDO compliant personality on top of JORM generic
* I/O sub-system.
* Copyright (C) 2001-2005 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*
* Contact: speedo@objectweb.org
*
* Authors: S.Chassande-Barrioz.
*
*/
package org.objectweb.speedo.pm.jdo.lib;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.jorm.api.PException;
import org.objectweb.perseus.persistence.api.NoDSIPersistenceException;
import org.objectweb.perseus.persistence.api.PersistenceException;
import org.objectweb.perseus.persistence.api.RolledBackPersistenceException;
import org.objectweb.speedo.api.ExceptionHelper;
import org.objectweb.speedo.api.SpeedoRuntimeException;
import org.objectweb.speedo.metadata.SpeedoVersion;
import org.objectweb.speedo.mim.api.DetachedLifeCycle;
import org.objectweb.speedo.mim.api.FetchPlanItf;
import org.objectweb.speedo.mim.api.HomeItf;
import org.objectweb.speedo.mim.api.LifeCycle;
import org.objectweb.speedo.mim.api.PersistentObjectItf;
import org.objectweb.speedo.mim.api.StateItf;
import org.objectweb.speedo.mim.jdo.api.JDOPersistentObjectItf;
import org.objectweb.speedo.mim.jdo.lib.JDOFetchPlan;
import org.objectweb.speedo.pm.jdo.api.JDOPOManagerItf;
import org.objectweb.speedo.pm.lib.AbstractPOManager;
import org.objectweb.speedo.query.api.QueryDefinition;
import org.objectweb.speedo.query.jdo.JDOExtent;
import org.objectweb.speedo.query.jdo.JDOQuery;
import org.objectweb.speedo.query.jdo.JDOQueryDefinitionImpl;
import org.objectweb.speedo.workingset.jdo.api.JDOTransactionItf;
import org.objectweb.util.monolog.api.BasicLevel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.jdo.Extent;
import javax.jdo.FetchPlan;
import javax.jdo.JDODataStoreException;
import javax.jdo.JDOException;
import javax.jdo.JDOUnsupportedOptionException;
import javax.jdo.JDOUserException;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;
import javax.jdo.datastore.JDOConnection;
import javax.jdo.datastore.Sequence;
import javax.jdo.listener.DeleteCallback;
import javax.jdo.listener.InstanceLifecycleListener;
/**
* Is a fractal component exporting the POManagerItf interface. This
* implementation delegates most of the JDO methods (javax.jdo.PersistenceManager)
* to the underlying TransactionPersistenceManager, the perseus component
* managing the concurrency, the caching and the loading aspect.
* In order to represents a working set (transtional or not) this PM is linked
* forever to an org.objectweb.speedo.workingset.jdo.api.JDOTransactionItf instance. The
* status of this JDOTransactionItf instance changes when this PM is allocated
* or closed, or when transaction demarcations are done through the
* javax.jdo.Transaction interface.
* This implementation uses a QueryManager for allocating CompiledQuery
* instance. Concerning the javax.jdo.Query implementation, this PM uses
* org.objectweb.speedo.query.lib.SpeedoQuery which are created each time
* (No pooling mechanism).
* The last dependencies is the JormFactory and a P
*
*
* @see javax.jdo.PersistenceManager
* @see org.objectweb.perseus.persistence.api.TransactionalPersistenceManager
* @see org.objectweb.speedo.mapper.api.JormFactory
* @see org.objectweb.speedo.pm.api.POManagerFactoryItf
* @see org.objectweb.speedo.query.api.QueryManager
* @see org.objectweb.speedo.query.api.CompiledQuery
* @see org.objectweb.speedo.workingset.jdo.api.JDOTransactionItf
*
* @author S.Chassande-Barrioz
*/
public class JDOPOManager
extends AbstractPOManager
implements JDOPOManagerItf,
BindingController{
/**
* The user object
*/
private Object userObject = null;
/**
* indicates if the cache must be ignore on queries
*/
boolean ignoreCache = true;
private HashMap userObjects = new HashMap();
public JDOPOManager() {
super();
}
public Query createQuery(Object o) {
JDOQuery sq = new JDOQuery();
sq.withPrefetch(prefetchOnQuery);
sq.setPOManager(this);
//initialize the fetch plan of the speedo query
sq.setFetchPlan(getFetchPlan());
sq.setQueryManager(queryManager);
sq.setIgnoreCache(ignoreCache);
sq.setLogger(loggerFactory.getLogger(logger.getName() + ".query"));
if (o!= null && o instanceof JDOQueryDefinitionImpl) {
sq.defineWith((JDOQueryDefinitionImpl) o);
}
return sq;
}
// IMPLEMENTATION OF THE JDOConnection INTERFACE //
//-----------------------------------------------//
public Object getNativeConnection() {
try {
if (((JDOTransactionItf) tx).getOptimistic()) {
return new DSConnectionFilter(
tx.getConnectionHolder().getCHConnectionForRead(),
true);
} else {
return new DSConnectionFilter(
tx.getConnectionHolder().getCHConnectionForWrite(),
false);
}
} catch(PersistenceException e) {
throw new JDODataStoreException("Impossible to allocate a native connection:", e);
}
}
// IMPLEMENTATION OF THE PersistentManager INTERFACE //
//---------------------------------------------------//
public boolean isClosed() {
return isPOMClosed();
}
public void addInstanceLifecycleListener(InstanceLifecycleListener l, Class[] classes) {
// TODO: support lifeCycle listener (add)
}
public void removeInstanceLifecycleListener(InstanceLifecycleListener classes) {
// TODO: support lifeCycle listener (remove)
}
public void flush() {
try {
speedoFlush();
} catch (PersistenceException e) {
throw new JDODataStoreException("Impossible to flush the working set");
}
}
public JDOConnection getDataStoreConnection() {
return this;
}
public FetchPlanItf speedoGetFetchPlan() {
if(fetchPlan == null){
fetchPlan = new JDOFetchPlan();
}
return fetchPlan;
}
public FetchPlan getFetchPlan() {
return (FetchPlan) speedoGetFetchPlan();
}
/**
* Fetches the Null PName associated to the PBinder of the persistent class
*/
public java.lang.Class getObjectIdClass(Class cls) {
bindPMThread();
if (cls == null) {
return null;
}
try {
return jf.getPBinder(cls).getNull().getClass();
} catch (PException e) {
Exception ie = ExceptionHelper.getNested(e);
logger.log(BasicLevel.ERROR,
"Error during the fetching of the manager of the class "
+ cls.getName(), ie);
throw new JDOException("", ie);
}
}
/**
* This method closes the PersistenceManager.
* @exception javax.jdo.JDOUserException if the transaction associated to
* the persistence manager is active.
* @exception javax.jdo.JDOFatalDataStoreException if there is a problem while
* releasing the persistence manager.
*/
public void close() {
closePOManager();
}
/**
* Return the JDOTransactionItf instance associated with a PersistenceManager.
* @return the JDOTransactionItf associated with this
* PersistenceManager.
*/
public javax.jdo.Transaction currentTransaction() {
bindPMThread();
return ((JDOTransactionItf) tx);
}
/**
* Mark an instance as no longer needed in the cache.
* @param o the instance to evict from the cache.
*/
public void evict(Object o) {
if (o == null)
return;
assertIsOpen();
bindPMThread();
JDOPersistentObjectItf sp = (JDOPersistentObjectItf) o;
if (tx.isActive() && sp.jdoIsDirty())
throw new JDOUserException("Impossible to evict a dirty " +
"instance attached to an active transaction");
try {
tpm.evict(tx, sp.getCeIdentifier(), false);
} catch (PersistenceException e) {
throw new JDOUserException(
"Impossible to evict the persistent object from the cache", e);
}
}
/** Mark an array of instances as no longer needed in the cache.
* @see #evict(java.lang.Object pc)
* @param pcs the array of instances to evict from the cache.
* @exception javax.jdo.JDOUserException if some instances cannot be removed.
*/
public void evictAll(Object[] pcs) {
Throwable[] th = new Throwable[pcs.length];
int lg = 0;
for (int i = 0; i < pcs.length; i++) {
try {
if (pcs[i] != null) {
evict(pcs[i]);
}
} catch (Throwable e) {
th[lg] = e;
lg++;
}
}
if (lg > 0) {
Throwable[] tfin = new Throwable[lg];
System.arraycopy(th, 0, tfin, 0, lg);
throw new JDOUserException("Impossible to evict", tfin);
}
}
/** Mark a Set of instances as no longer needed in the cache.
* @see #evict(java.lang.Object pc)
* @param pcs the Set of instance to evict from the cache.
*/
public void evictAll(Collection pcs) {
evictAll(pcs.toArray());
}
/** Mark all persistent-nontransactional instances as no longer needed
* in the cache. It transitions all persistent-nontransactional instances to
* hollow. Transactional instances are subject to eviction based on the
* RetainValues setting.
* @see #evict(java.lang.Object pc)
*/
public void evictAll() {
assertIsOpen();
try {
tpm.evictAll(tx, false);
} catch (PersistenceException e) {
throw new JDOException("Error during the eviction of all cache entries: ",
ExceptionHelper.getNested(e));
}
}
/** Refresh the state of the instance from the data store.
* <P>In an optimistic transaction, the state of instances in the cache
* might not match the state in the data store. This method is used to
* reload the state of the instance from the data store so that a subsequent
* commit is more likely to succeed.
* <P>Outside a transaction, this method will refresh nontransactional
* state.
* @param o the instance to refresh.
*/
public void refresh(Object o) {
if (o == null)
return;
PersistentObjectItf sp = (PersistentObjectItf) o;
assertIsOpen();
bindPMThread();
assertIsPO(sp, "refresh");
assertPOManager(sp);
if (!sp.speedoIsActive())
throw new JDOUserException("Refresh on a transient instance.");
speedoRefresh(sp, new HashMap(), new ArrayList());
}
public void speedoRefresh(PersistentObjectItf sp, Map map, Collection fgHints){
try {
if (map != null && !map.containsKey(sp.getPName())) {
map.put(sp.getPName(), sp);
tpm.refresh(tx, sp);
StateItf sa = (StateItf) tpm.readIntention(tx, sp, null);
sa.refresh(this, map, fgHints);
}
} catch (PersistenceException e) {
throw new JDOException("Impossible to refresh a persistent instance", e);
}
}
/** Refresh the state of an array of instances from the data store.
* @see #refresh(java.lang.Object pc)
* @param pcs the array of instances to refresh.
* object.
*/
public void refreshAll(Object[] pcs) {
Throwable[] th = new Throwable[pcs.length];
int lg = 0;
for (int i = 0; i < pcs.length; i++) {
try {
if (pcs[i] != null) {
refresh(pcs[i]);
}
} catch (Throwable e) {
th[lg] = e;
lg++;
}
}
if (lg > 0) {
Throwable[] tfin = new Throwable[lg];
System.arraycopy(th, 0, tfin, 0, lg);
throw new JDOUserException("Impossible to refresh", tfin);
}
}
/** Refresh the state of a Set of instances from the data store.
* @see #refresh(java.lang.Object pc)
* @param pcs the Set of instances to refresh.
*/
public void refreshAll(Collection pcs) {
refreshAll(pcs.toArray());
}
/** Refresh the state of all applicable instances from the data store.
* <P>If called with an active transaction, all transactional instances
* will be refreshed. If called outside an active transaction, all
* nontransactional instances will be refreshed.
* @see #refresh(java.lang.Object pc)
*/
public void refreshAll() {
assertIsOpen();
if (!tx.isActive()) {
return;
}
Set entries = tx.entries();
int size = entries.size();
if (size == 0) {
return;
}
Object[] sps = new Object[size];
Iterator it = entries.iterator();
int i=0;
while(it.hasNext() && i<sps.length) {
org.objectweb.perseus.persistence.api.State s = (org.objectweb.perseus.persistence.api.State) it.next();
sps[i] = s.getCacheEntry();
i++;
}
refreshAll(sps);
}
public void refreshAll(JDOException arg0) {
//TODO: review the refreshAll(JDOException) behavior
refreshAll();
}
/**
* Create a new Query with no elements.
* @return the new Query.
*/
public Query newQuery() {
assertIsOpen();
bindPMThread();
return createQuery(null);
}
public Query newQuery(String query) {
assertIsOpen();
bindPMThread();
//TODO: Implements newQuery(String)
return createQuery(null);
}
public Query newNamedQuery(Class klass, String name) {
try {
QueryDefinition qd = ((HomeItf) jf.getPClassMapping(klass)).getNamedQuery(name);
return createQuery(qd);
} catch (PException e) {
Exception ie = ExceptionHelper.getNested(e);
logger.log(BasicLevel.ERROR,
"Error during the fetching of the manager of the class "
+ klass.getName(), ie);
throw new JDOException("Error during the fetching of the manager of the class ", ie);
}
}
/**
* Create a new Query using elements from another Query.
* The other Query must have been created by the same JDO implementation.
* It might be active in a different PersistenceManager or might have been
* serialized and restored.
* <P>All of the settings of the other Query are copied to this Query,
* except for the candidate Set or Extent.
* @return the new Query
* @param compiled another Query from the same JDO implementation
*/
public Query newQuery(Object compiled) {
assertIsOpen();
bindPMThread();
return createQuery(compiled);
}
/**
* Create a new Query using the specified language.
* @param language the language of the query parameter
* @param query the query, which is of a form determined by the language
* @return the new Query
*/
public Query newQuery(String language, Object query) {
assertIsOpen();
bindPMThread();
if (language.compareTo("java.jdo.query.toVerify") == 0) {
return createQuery(query);
} else
throw new JDOUnsupportedOptionException("Language \"" + language
+ "\"" + " is not supported by this jdo implementation");
}
/**
* Create a new Query specifying the Class of the candidate instances.
* @param cls the Class of the candidate instances
* @return the new Query
*/
public Query newQuery(Class cls) {
assertIsOpen();
bindPMThread();
Query q = createQuery(null);
q.setClass(cls);
if (getObjectIdClass(cls) == null)
throw new JDOUnsupportedOptionException(
"There is a problem with the specified class");
return q;
}
public Query newQuery(Extent extent) {
assertIsOpen();
bindPMThread();
JDOQuery q = (JDOQuery) createQuery(null);
Class c = extent.getCandidateClass();
q.setIncludeSubClasses(extent.hasSubclasses());
q.setClass(c);
if (getObjectIdClass(c) == null)
throw new JDOUnsupportedOptionException(
"There is a problem with the specified class");
return q;
}
public Query newQuery(Extent extent, String filter) {
assertIsOpen();
bindPMThread();
Query q = newQuery(extent);
q.setFilter(filter);
return q;
}
/**
* Create a new Query with the Class of the candidate instances and
* candidate Set.
* @param cls the Class of results
* @param cln the Set of candidate instances
* @return the new Query
*/
public Query newQuery(Class cls, Collection cln) {
assertIsOpen();
bindPMThread();
Query q = createQuery(null);
q.setClass(cls);
q.setCandidates(cln);
return q;
}
/**
* Create a new Query with the Class of the candidate instances and filter.
* @param cls the Class of results
* @param filter the filter for candidate instances
* @return the new Query
*/
public Query newQuery(Class cls, String filter) {
assertIsOpen();
bindPMThread();
Query q = createQuery(null);
q.setClass(cls);
q.setFilter(filter);
return q;
}
/**
* Create a new Query with the Class of the candidate instances,
* candidate Set, and filter.
* @param cls the Class of candidate instances
* @param cln the Set of candidate instances
* @param filter the filter for candidate instances
* @return the new Query
*/
public Query newQuery(Class cls, Collection cln, String filter) {
assertIsOpen();
bindPMThread();
Query q = createQuery(null);
q.setClass(cls);
q.setCandidates(cln);
q.setFilter(filter);
return q;
}
/** Not implemented. The PersistenceManager manages a collection of
* instances in the data store based on the class of the instances. This
* method returns a Extent of instances in the data store that might be
* iterated or given to a Query. The Extent itself might not reference any
* instances, but only hold the class name and an
* indicator whether subclasses are included in the Extent.
* @param persistenceCapableClass Class of instances
* @param subclasses whether to include instances of subclasses
* @return an Extent of the specified Class
*/
public Extent getExtent(Class persistenceCapableClass,
boolean subclasses) {
assertIsOpen();
bindPMThread();
return new JDOExtent(
persistenceCapableClass, subclasses, this, jf, prefetchOnExtent, logger);
}
public Extent getExtent(Class arg0) {
return getExtent(arg0, true);
}
/** This method locates a persistent instance in the cache of instances
* managed by this PersistenceManager. The getObjectById method attempts
* to find an instance in the cache with the specified JDO identity.
* The oid parameter object might have been returned by an earlier call
* to getObjectId or getTransactionalObjectId, or might have been
* constructed by the application.
* @see #getObjectId(java.lang.Object pc)
* @see #getTransactionalObjectId(java.lang.Object pc)
* @return the PersistenceCapable instance with the specified
* ObjectId
* @param oid an ObjectId
* @param validate if the existence of the instance is to be validated. The
* flag is ignored in this implementation.
*/
public Object getObjectById(Object oid, boolean validate) {
assertIsOpen();
bindPMThread();
return speedoGetObjectById(oid, validate);
}
public Object getObjectById(Class arg0, Object oid) {
assertIsOpen();
bindPMThread();
return speedoGetObjectById(newObjectIdInstance(arg0, oid), false);
}
public Object getObjectById(Object oid) {
assertIsOpen();
bindPMThread();
return speedoGetObjectById(oid, false);
}
public Collection getObjectsById(Collection arg0, boolean validate) {
if (arg0 == null) {
return Collections.EMPTY_LIST;
}
assertIsOpen();
bindPMThread();
ArrayList al = new ArrayList(arg0.size());
for(Iterator it = arg0.iterator(); it.hasNext();) {
Object oid = it.next();
if (oid == null) {
al.add(null);
continue;
}
try {
al.add(speedoGetObjectById(oid, validate));
} catch (Exception e) {
al.add(null);
}
}
return al;
}
public Collection getObjectsById(Collection arg0) {
return getObjectsById(arg0, true);
}
public Object[] getObjectsById(Object[] arg0, boolean arg1) {
if (arg0 == null) {
return new Object[0];
}
assertIsOpen();
bindPMThread();
Object[] objs = new Object[arg0.length];
for(int i=0; i<arg0.length; i++) {
Object oid = arg0[i];
if (oid == null) {
objs[i] = null;
continue;
}
try {
objs[i] = speedoGetObjectById(oid, arg1);
} catch (Exception e) {
objs[i] = null;
}
}
return objs;
}
public Object[] getObjectsById(Object[] arg0) {
return getObjectsById(arg0, true);
}
public Object speedoGetObjectById(Object oid, boolean validate) {
if (oid == null)
return null;
try {
try {
return super.speedoGetObject(oid, null, validate);
} catch (SpeedoRuntimeException e) {
throw (Exception) e.getCause();
}
} catch (NoDSIPersistenceException e) {
throw new JDOUserException(
"No data store instance matching to the specified identifier: "
+ oid, ExceptionHelper.getNested(e));
} catch (RolledBackPersistenceException e) {
throw ((JDOTransactionItf) tx).rollBackOnInternalError(e);
} catch (Exception e) {
Exception ie = ExceptionHelper.getNested(e);
logger.log(BasicLevel.ERROR,
"Impossible to fetch a persistent object with the identifier: " + oid, ie);
throw new JDOException("", ie);
}
}
/** The ObjectId returned by this method represents the JDO identity of
* the instance. The ObjectId is a copy (clone) of the internal state
* of the instance, and changing it does not affect the JDO identity of
* the instance.
* @see #getTransactionalObjectId(java.lang.Object pc)
* @see #getObjectById(java.lang.Object oid, boolean validate)
* @param pc the PersistenceCapable instance
* @return the ObjectId of the instance
*/
public Object getObjectId(Object pc) {
assertIsOpen();
bindPMThread();
//the object must be persistence capable. otherwise, it doesn't have an
//objectid
try {
assertIsPO(pc, "");
} catch (Exception e) {
return null;
}
PersistentObjectItf sp = (PersistentObjectItf) pc;
if (!sp.speedoIsActive())
throw new JDOUserException("Object non persistent.");
assertPOManager(sp);
try {
return pnc.encodeAbstract(sp.getPName());
} catch (PException e) {
throw new JDOException(
"Problem while encoding persistent name.",
new Exception[]{ExceptionHelper.getNested(e)});
}
}
public Object getEncodedPName(PersistentObjectItf po) {
return getObjectId(po);
}
/** Not implemented. The ObjectId returned by this method represents the JDO
* identity of the instance. The ObjectId is a copy (clone) of the internal
* state of the instance, and changing it does not affect the JDO identity
* of the instance.
* <P>If the object identity is being changed in the transaction, by the
* application modifying one or more of the application key fields,
* then this method returns the current identity in the transaction.
* <P>If there is no transaction in progress, or if none of the key fields
* is being modified, then this method will return the same value as
* getObjectId.
* @see #getObjectId(java.lang.Object pc)
* @see #getObjectById(java.lang.Object oid, boolean validate)
* @param o a PersistenceCapable instance
* @return the ObjectId of the instance
*/
public Object getTransactionalObjectId(Object o) {
assertIsOpen();
bindPMThread();
throw new JDOUnsupportedOptionException("Not implemented.");
}
/** Make the transient instance persistent in this PersistenceManager.
* This method must be called in an active transaction.
* The PersistenceManager assigns an ObjectId to the instance and
* transitions it to persistent-new.
* The instance will be managed in the Extent associated with its Class.
* The instance will be put into the data store at commit.
* The closure of instances of PersistenceCapable classes
* reachable from persistent
* fields will be made persistent at commit. [This is known as
* persistence by reachability.]
* @param o a transient instance of a Class that implements
* PersistenceCapable
*/
public Object makePersistent(Object o) {
assertIsOpen();
bindPMThread();
assertIsPO(o, "");
if (o == null)
return null;
JDOPersistentObjectItf jdopo = (JDOPersistentObjectItf) o;
if (jdopo.speedoGetReferenceState().getDetachedStatus() == DetachedLifeCycle.DETACHED_NONE) {
return speedoMakePersistent((PersistentObjectItf) o, null);
} else {
return speedoAttachCopy(o, new HashMap());
}
}
public Object speedoMakePersistent(PersistentObjectItf po, Map map) {
JDOPersistentObjectItf jdopo = (JDOPersistentObjectItf) po;
if (jdopo.jdoIsPersistent())
return po;
if (!jdopo.speedoIsActive()) {
if (jdopo.speedoGetReferenceState().getDetachedStatus() != DetachedLifeCycle.DETACHED_NONE) {
return null;
}
}
synchronized(jdopo) {
if (jdopo.jdoIsPersistent())
return po;
try {
return speedoPersist(po, map);
} catch (Exception e) {
try {
jdopo.init(null);
} catch (PException e1) {
logger.log(BasicLevel.WARN, "Error during unbinding:", e1);
}
if (e instanceof RolledBackPersistenceException) {
throw ((JDOTransactionItf) tx).rollBackOnInternalError(e);
} else {
throw new JDODataStoreException(
"Problem while making persistent.",
new Exception[]{ExceptionHelper.getNested(e)});
}
}
}
}
/** Make an array of instances persistent.
* @param pcs an array of transient instances
* @exception javax.jdo.JDOUserException if an object cannot be made persistent.
* @see #makePersistent(java.lang.Object pc)
*/
public Object[] makePersistentAll(Object[] pcs) {
if (pcs == null || pcs.length == 0)
return null;
assertIsOpen();
bindPMThread();
Exception[] th = new Exception[pcs.length];
//the list of returned persistent objects
Object[] pos = new Object[pcs.length];
int lg = 0;
//HashMap in case of detach
HashMap map = new HashMap(1);
for (int i = 0; i < pcs.length; i++) {
try {
assertIsPO(pcs[i], "");
if (true) {
pos[i] = speedoMakePersistent((PersistentObjectItf) pcs[i], null);
} else {
pos[i] = speedoAttachCopy(pcs[i], map);
}
} catch (Exception e) {
th[lg] = e;
lg++;
}
}
if (lg > 0) {
Exception[] tfin = new Exception[lg];
System.arraycopy(th, 0, tfin, 0, lg);
throw new JDOUserException("Impossible to make persistent : ", tfin);
} else {
return pos;
}
}
/** Make a Set of instances persistent.
* @param pcs a Set of transient instances
* @see #makePersistent(java.lang.Object pc)
*/
public Collection makePersistentAll(Collection pcs) {
if (pcs == null || pcs.size() == 0)
return null;
Object[] pos = makePersistentAll(pcs.toArray());
return Arrays.asList(pos);
}
/** Delete the persistent instance from the data store.
* This method must be called in an active transaction.
* The data store object will be removed at commit.
* Unlike makePersistent, which makes the closure of the instance
* persistent, the closure of the instance is not deleted from the data
* store.
* This method has no effect if the instance is already deleted in the
* current transaction.
* @param o a persistent instance
* @exception javax.jdo.JDOUserException if the instance is transient or managed by
* another PersistenceManager.
*/
public void deletePersistent(Object o) {
assertIsOpen();
bindPMThread();
speedoDeletePersistent(o);
}
public void speedoDeletePersistent(Object o) {
JDOPersistentObjectItf sp = (JDOPersistentObjectItf) o;
// Verify the instance is managed by this persistence manager
assertPOManager(sp);
// Verify the transaction is active
if (!tx.isActive()) {
throw new JDOUserException("DeletePersistent " +
"must be called in an active transaction");
}
StateItf sa = null;
try {
if (!sp.jdoIsPersistent()) {
throw new JDOUserException(
"DeletePersistent on an instance non persistent.");
}
if (sp.jdoIsDeleted()) {
return;
}
sp.speedoGetHome().sendEvent(HomeItf.PRE_REMOVE, sp, null);
sa = (StateItf) tpm.unexport(tx, sp);
sp.speedoGetHome().sendEvent(HomeItf.POST_REMOVE, sp, null);
} catch (RolledBackPersistenceException e) {
throw ((JDOTransactionItf) tx).rollBackOnInternalError(e);
} catch (PersistenceException e) {
throw new JDOException("", ExceptionHelper.getNested(e));
}
//remove the multivalued fields and cascade delete
sa.deletePersistent(this);
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG,
"Delete a persistent instance, identifier=" + sp.getPName());
}
}
public void speedoDeletePersistent(Object oid, Class pc) {
// Verify the transaction is active
if (!tx.isActive()) {
throw new JDOUserException("DeletePersistent " +
"must be called in an active transaction");
}
boolean mustLoad = DeleteCallback.class.isAssignableFrom(pc);
if (!mustLoad) {
HomeItf home;
try {
home = (HomeItf) jf.getPClassMapping(pc);
} catch (PException e) {
throw new JDOException("", e);
}
mustLoad = home.hasInstanceLifeCycleListeners();
if (!mustLoad) {
//TODO: manage cascade delete
}
}
if (mustLoad) {
PersistentObjectItf po = (PersistentObjectItf) speedoGetObjectById(oid, false);
speedoDeletePersistent(po);
return;
}
//no listener or callback
//TODO
}
public void deleteByQuery(QueryDefinition qd) {
}
/** Delete an array of instances from the data store.
* @param pcs a Set of persistent instances
* @see #deletePersistent(java.lang.Object pc)
*/
public void deletePersistentAll(Object[] pcs) {
if (pcs == null)
return;
assertIsOpen();
bindPMThread();
Throwable[] th = new Throwable[pcs.length];
int lg = 0;
for (int i = 0; i < pcs.length; i++) {
try {
speedoDeletePersistent(pcs[i]);
} catch (Throwable e) {
th[lg] = e;
lg++;
}
}
if (lg > 0) {
Throwable[] tfin = new Throwable[lg];
System.arraycopy(th, 0, tfin, 0, lg);
throw new JDOUserException
("Impossible to delete persistent : ", tfin);
}
}
/** Delete a Set of instances from the data store.
* @param pcs a Set of persistent instances
* @see #deletePersistent(java.lang.Object pc)
*/
public void deletePersistentAll(Collection pcs) {
if (pcs == null)
return;
deletePersistentAll(pcs.toArray());
}
/** Make an instance transient, removing it from management by this
* PersistenceManager.
* <P>The instance loses its JDO identity and it is no longer associated
* with any PersistenceManager. The state of fields is preserved unchanged.
* @param o the instance to make transient.
* @exception javax.jdo.JDOUserException if the instance is dirty.
*/
public void makeTransient(Object o) {
assertIsOpen();
bindPMThread();
if (o == null || !(o instanceof JDOPersistentObjectItf)
|| !((JDOPersistentObjectItf) o).jdoIsPersistent()) {
return;
}
JDOPersistentObjectItf sp = (JDOPersistentObjectItf) o;
synchronized(sp) {
if (sp.jdoIsDirty()) {
throw new JDOUserException("Try to make transient a dirty instance.");
}
try {
tpm.unbind(tx, sp);
} catch (PersistenceException e) {
throw new JDOUserException("Impossible to make transient the persistent instance: ",
ExceptionHelper.getNested(e));
}
}
}
/** Make an array of instances transient, removing them from management by
* this PersistenceManager.
* @see #makeTransient(java.lang.Object pc)
* @param pcs the instances to make transient.
*/
public void makeTransientAll(Object[] pcs) {
if (pcs == null)
return;
Throwable[] th = new Throwable[pcs.length];
int lg = 0;
for (int i = 0; i < pcs.length; i++) {
try {
makeTransient(pcs[i]);
} catch (Throwable e) {
th[lg] = e;
lg++;
}
}
if (lg > 0) {
Throwable[] tfin = new Throwable[lg];
System.arraycopy(th, 0, tfin, 0, lg);
throw new JDOUserException("Impossible to make transient: ", tfin);
}
}
/** Make a Set of instances transient, removing them from management
* by this PersistenceManager.
* <P>The instances lose their JDO identity and they are no longer
* associated with any PersistenceManager. The state of fields is preserved
* unchanged.
* @param pcs the instances to make transient.
*/
public void makeTransientAll(Collection pcs) {
if (pcs == null)
return;
makeTransientAll(pcs.toArray());
}
/** Make an instance subject to transactional boundaries.
* @see javax.jdo.PersistenceManager#makeTransactional
* @param o the instance to make transactional.
*/
public void makeTransactional(Object o) {
//TODO: support the makeTransactional method
throw new JDOUnsupportedOptionException("not yet implemented");
}
/** Make an array of instances subject to transactional boundaries.
* @param pcs the array of instances to make transactional.
* @see #makeTransactional(java.lang.Object pc)
*/
public void makeTransactionalAll(Object[] pcs) {
if (pcs == null || pcs.length == 0)
return;
Throwable[] th = new Throwable[pcs.length];
int lg = 0;
for (int i = 0; i < pcs.length; i++) {
try {
makeTransactional(pcs[i]);
} catch (Throwable e) {
th[lg] = e;
lg++;
}
}
if (lg > 0) {
Throwable[] tfin = new Throwable[lg];
System.arraycopy(th, 0, tfin, 0, lg);
throw new JDOUserException
("Impossible to make transactional : ", tfin);
}
}
/** Make a Set of instances subject to transactional boundaries.
* @param pcs the Set of instances to make transactional.
* @see #makeTransactional(java.lang.Object pc)
*/
public void makeTransactionalAll(Collection pcs) {
if (pcs == null || pcs.size() == 0)
return;
makeTransactionalAll(pcs.toArray());
}
public void makeNontransactional(Object o) {
JDOPersistentObjectItf sp = (JDOPersistentObjectItf) o;
//preconditions
assertIsOpen();
bindPMThread();
assertIsPO(sp, "");
assertPOManager(sp);
if (sp.jdoIsDirty())
throw new JDOUserException("Try to make non-transactional a dirty instance.");
sp.speedoGetState().speedoChangeStatus(LifeCycle.ACTION_MAKENONTRANSACTIONAL);
}
public void makeNontransactionalAll(Object[] pcs) {
if (pcs == null || pcs.length == 0)
return;
ArrayList th = new ArrayList(pcs.length);
for (int i = 0; i < pcs.length; i++) {
try {
makeNontransactional(pcs[i]);
} catch (Throwable e) {
th.add(e);
}
}
if (th.size() > 0) {
throw new JDOUserException("Impossible to make non transactional : ",
(Throwable[]) th.toArray(new Throwable[0]));
}
}
public void makeNontransactionalAll(Collection pcs) {
if (pcs == null || pcs.size() == 0)
return;
makeNontransactionalAll(pcs.toArray());
}
public void setUserObject(Object o) {
bindPMThread();
userObject = o;
}
/** The application can manage the PersistenceManager instances
* more easily by having an application object associated with each
* PersistenceManager instance.
* @return the user object associated with this PersistenceManager
* @see #setUserObject
*/
public Object getUserObject() {
bindPMThread();
return userObject;
}
public PersistenceManagerFactory getPersistenceManagerFactory() {
return (PersistenceManagerFactory) pmf;
}
/** Set the Multithreaded flag for this PersistenceManager. Applications
* that use multiple threads to invoke methods or access fields from
* instances managed by this PersistenceManager must set this flag to true.
* Instances managed by this PersistenceManager include persistent or
* transactional instances of PersistenceCapable classes, as well as
* helper instances such as Query, JDOTransactionItf, or Extent.
* @param flag the Multithreaded setting.
*/
public void setMultithreaded(boolean flag) {
semaphore.init(flag);
}
/** Get the current Multithreaded flag for this PersistenceManager.
* This option is ignored by the implementation.
* @see #setMultithreaded
* @return the Multithreaded setting.
*/
public boolean getMultithreaded() {
return semaphore.on;
}
/** Set the ignoreCache parameter for queries.
* @param flag the ignoreCache setting.
*/
public void setIgnoreCache(boolean flag) {
ignoreCache = flag;
}
/** Get the ignoreCache setting for queries.
* @return the ignoreCache setting.
* @see #setIgnoreCache
*/
public boolean getIgnoreCache() {
return ignoreCache;
}
public Object newObjectIdInstance(Class aClass, Object s) {
assertIsOpen();
bindPMThread();
try {
return pnc.decodeAbstract(s, aClass);
} catch (PException e) {
throw new JDOUserException("Invalid persistent object identifier "
+ s + " for the class " + aClass, new Exception[]{e});
}
}
public void retrieve(Object o) {
assertIsOpen();
bindPMThread();
assertIsPO(o, "retrieve(Object)");
speedoRetrieve((PersistentObjectItf) o, new HashMap(), new ArrayList());
}
public void speedoRetrieve(PersistentObjectItf sp, Map map, Collection fgHints){
try {
if (map != null && !map.containsKey(sp.getPName())) {
map.put(sp.getPName(), sp);
tpm.refresh(tx, sp);
StateItf sa = (StateItf) tpm.readIntention(tx, sp, null);
sa.retrieve(this, map, fgHints);
}
} catch (PersistenceException e) {
throw new JDOException("Impossible to retrieve a persistent instance", e);
}
}
public void retrieveAll(Collection pcs) {
assertIsOpen();
bindPMThread();
if (pcs == null) {
return;
}
for(Iterator it = pcs.iterator(); it.hasNext();) {
Object o = it.next();
assertIsPO(o, "retrieve(Collection)");
speedoRetrieve((PersistentObjectItf) o, new HashMap(), new ArrayList());
}
}
public void retrieveAll(Object[] pcs) {
assertIsOpen();
bindPMThread();
if (pcs == null) {
return;
}
for(int i = 0; i<pcs.length; i++) {
assertIsPO(pcs[i], "retrieve(Collection)");
if(((PersistentObjectItf) pcs[i]).speedoGetReferenceState() != null)
speedoRetrieve((PersistentObjectItf) pcs[i], new HashMap(), new ArrayList());
}
}
public void retrieveAll(Collection collection, boolean b) {
retrieveAll(collection);
}
public void retrieveAll(Object[] objects, boolean b) {
retrieveAll(objects);
}
/**
* Make a detached copy of the persitent object o and return it.
* Only the fields belonging to the fetch group are reachable.
* @param o
* @return the detached copy of the persistent object
*/
public Object detachCopy(Object o){
assertIsOpen();
assertIsPO(o, "detachCopy");
return speedoDetachCopy((PersistentObjectItf)o, new HashMap(), new ArrayList());
}
public Object speedoDetachCopy(PersistentObjectItf po, Map map, Collection fgHints){
JDOPersistentObjectItf jdopo = (JDOPersistentObjectItf) po;
//check the meta info about the detachability of the class
if(jdopo.jdoIsPersistent()){
if(jdopo.jdoIsDeleted()){
//persistent_deleted
if(!jdopo.jdoIsNew())
throw new JDOUserException("This object cannot be detached: it has been deleted from the datastore.");
}
}
else{
//makePersistent
speedoMakePersistent(jdopo, null);
}
if(!jdopo.speedoGetHome().isDetachable()){
throw new JDOUserException("This class cannot be detached: it has not been defined as detachable in the jdo file.");
}
jdopo.speedoGetHome().sendEvent(HomeItf.PRE_DETACH, jdopo, null);
//persistent_new or persistent_dirty: updated with object id and version
if(jdopo.jdoIsTransactional() && jdopo.jdoIsDirty()){
try{
StateItf sa = (StateItf) tpm.writeIntention(tx, jdopo, null);
if(!sa.hasBeenFlush()){
//flush
tpm.flush(tx, sa);
}
} catch (Exception e) {
throw new JDODataStoreException(
"Problem while flushing a persistent object in order to detach a copy.",
new Exception[]{ExceptionHelper.getNested(e)});
}
}
//the core processing
//avoid cycles using a map
try{
synchronized(fgHints){
PersistentObjectItf copy = jdopo.speedoGetHome().detachCopy(jdopo, this, map, null, fgHints);
if (jdopo.speedoGetHome().getVersioningStrategy() == SpeedoVersion.VERSION_NUMBER) {
copy.speedoGetReferenceState().speedoChangeVersion();
}
return copy;
}
}
catch(Exception e){
throw new JDOUserException("Detach cannot be performed", new Exception[]{ExceptionHelper.getNested(e)});
} finally {
jdopo.speedoGetHome().sendEvent(HomeItf.POST_DETACH, jdopo, null);
}
}
/**
* Create a detached copy for each element of collection (assuming each element is persistent).
* If there are duplicates in collection, the corresponding detached copy is used for each such duplicate.
* @param collection
* @return the collection of the detached copies in the same order than the parameter
*/
public Collection detachCopyAll(Collection collection){
assertIsOpen();
if (collection == null)
return null;
makePersistentAll(collection);
ArrayList copies = new ArrayList();
for (Iterator it = collection.iterator(); it.hasNext();){
copies.add(detachCopy(it.next()));
}
return copies;
}
public Object[] detachCopyAll(Object[] objects){
assertIsOpen();
if(objects == null)
return null;
makePersistentAll(objects);
Object[] copies = new Object[objects.length];
for (int i = 0; i < objects.length; i++){
copies[i] = detachCopy(objects[i]);
}
return copies;
}
/**
* Apply the changes contained in the detached object to the corresponding persistent instance in the cache.
* @param detached
* @param map is the attachement context
* @return the peristent object containg attached values
*/
public Object speedoAttachCopy(Object detached, Map map){
// if the detached object is null
// then do nothing
if (detached == null)
return null;
Object o = map.get(detached);
// if the object is being or has been processed
// then return the attached copy
if (o != null)
return o;
Object oid = ((PersistentObjectItf)detached).speedoGetEncodedPName();
PersistentObjectItf sp = null;
try {
if (oid == null) {
//make the object persistent
speedoMakePersistent((PersistentObjectItf) detached, map);
//return detached;
sp = (PersistentObjectItf) detached;
} else {
sp = (PersistentObjectItf) speedoGetObjectById(oid, false);
}
sp.speedoGetHome().sendEvent(HomeItf.PRE_ATTACH, sp, null);
StateItf sar = sp.speedoGetHome().readIntention(sp, null);
//if made persistent in this method
// force the state to detached_dirty
if (oid == null) {
sar.forceDetachedDirty();
}
//call the attach method on the po
sp.speedoGetHome().attachCopy(sp, this, map, detached, sar);
// if made persistent in this method
// restore the state to detached_none
if (oid == null) {
sar.restoreDetachedNone();
}
//change the version on attach
sar.speedoChangeVersion();
sp.speedoGetHome().sendEvent(HomeItf.POST_ATTACH, sp, null);
return sp;
} catch (Exception e) {
Exception ie = ExceptionHelper.getNested(e);
String msg = "Impossible to attach a copy of the persistent object with the identifier: " + oid;
logger.log(BasicLevel.INFO, msg, ie);
throw (e instanceof JDOException
? (JDOException) e
: new JDOException(msg, ie));
}
}
public Object getUserObject(Object arg0) {
return userObjects.get(arg0);
}
public Object putUserObject(Object arg0, Object arg1) {
return userObjects.put(arg0, arg1);
}
public Object removeUserObject(Object arg0) {
return userObjects.remove(arg0);
}
public void checkConsistency() {
flush();
// TODO: verify consistency of state in the WS
}
public Sequence getSequence(String name) {
Sequence s = (Sequence) pmf.getSequenceManager().getSequence(name);
if (s == null) {
throw new JDOUserException("The sequence " + name + " has not been found."
+ "Be sure that one class of the package the sequence belongs to has been loaded.");
}
return s;
}
public Object newInstance(Class arg0) {
if (arg0 == null) {
return null;
}
if (arg0.isInterface()) {
throw new JDOUserException(
"Speedo does not support persistent interface currently: "
+ arg0.getName());
} else {
try {
return arg0.newInstance();
} catch (Exception e) {
throw new JDOUserException(
"Speedo does not support persistent abstract class currently: "
+ arg0.getName());
}
}
}
public void closePOManager() {
super.closePOManager();
if (nbUse == 0) {
userObject = null;
}
}
protected void resetPMOnOpen(Object connectionspec) {
((JDOTransactionItf) tx).setOptimistic(((PersistenceManagerFactory) pmf).getOptimistic());
setIgnoreCache(((PersistenceManagerFactory) pmf).getIgnoreCache());
boolean multithreaded = ((PersistenceManagerFactory) pmf).getMultithreaded();
if (multithreaded != semaphore.on)
semaphore.init(multithreaded);
}
public void makeTransient(Object o, boolean useFetchPlan) {
if (!useFetchPlan) {
makeTransient(o);
} else {
//TODO: implement
}
}
public void makeTransientAll(Object[] os, boolean useFetchPlan) {
if (!useFetchPlan) {
makeTransientAll(os);
} else {
//TODO: implement
}
}
public void makeTransientAll(Collection os, boolean useFetchPlan) {
if (!useFetchPlan) {
makeTransientAll(os);
} else {
//TODO: implement
}
}
public void retrieve(Object o, boolean FGOnly) {
if (!FGOnly) {
retrieve(o);
} else {
//TODO: implement
}
}
/* (non-Javadoc)
* @see javax.jdo.PersistenceManager#getDetachAllOnCommit()
*/
public boolean getDetachAllOnCommit() {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see javax.jdo.PersistenceManager#setDetachAllOnCommit(boolean)
*/
public void setDetachAllOnCommit(boolean arg0) {
// TODO Auto-generated method stub
}
}