mirror of https://github.com/apache/openjpa.git
OPENJPA-126: EntityManager serializability. Also includes a fix to make LoadListener.afterRefresh() work. Committing directly (not via remote queue) as I'm about to lose my internet connection for a while. Hopefully, my local testing is accurate.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@597155 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
fad6f35201
commit
5018dfaa88
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
package org.apache.openjpa.jdbc.kernel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.sql.Connection;
|
||||
import java.util.Collection;
|
||||
|
||||
|
@ -134,5 +137,10 @@ public abstract class AbstractJDBCSavepointManager
|
|||
AbstractJDBCSavepointManager.this.setDataStore(this);
|
||||
super.save(states);
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out)
|
||||
throws IOException {
|
||||
throw new NotSerializableException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -582,8 +582,8 @@ public class EmbedFieldStrategy
|
|||
return _owner;
|
||||
}
|
||||
|
||||
public ValueMetaData getOwnerMetaData() {
|
||||
return _vmd;
|
||||
public int getOwnerIndex() {
|
||||
return _vmd.getFieldMetaData().getIndex();
|
||||
}
|
||||
|
||||
public boolean isEmbedded() {
|
||||
|
|
|
@ -245,6 +245,36 @@ public class PCEnhancer {
|
|||
+ cls.getName().replace('.', '$') + "$pcsubclass";
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not <code>className</code> is the name for a
|
||||
* dynamically-created persistence-capable subclass.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static boolean isPCSubclassName(String className) {
|
||||
return className.startsWith(Strings.getPackageName(PCEnhancer.class))
|
||||
&& className.endsWith("$pcsubclass");
|
||||
}
|
||||
|
||||
/**
|
||||
* If <code>className</code> is a dynamically-created persistence-capable
|
||||
* subclass name, returns the name of the class that it subclasses.
|
||||
* Otherwise, returns <code>className</code>.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static String toManagedTypeName(String className) {
|
||||
if (isPCSubclassName(className)) {
|
||||
className = className.substring(
|
||||
Strings.getPackageName(PCEnhancer.class).length() + 1);
|
||||
className = className.substring(0, className.lastIndexOf("$"));
|
||||
// this is not correct for nested PCs
|
||||
className = className.replace('$', '.');
|
||||
}
|
||||
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Supply configuration, type, and metadata.
|
||||
*/
|
||||
|
@ -2718,6 +2748,9 @@ public class PCEnhancer {
|
|||
return;
|
||||
|
||||
if (getCreateSubclass()) {
|
||||
// ##### what should happen if a type is Externalizable? It looks
|
||||
// ##### like Externalizable classes will not be serialized as PCs
|
||||
// ##### based on this logic.
|
||||
if (!Externalizable.class.isAssignableFrom(
|
||||
_meta.getDescribedType()))
|
||||
addSubclassSerializationCode();
|
||||
|
|
|
@ -121,6 +121,17 @@ public class PCRegistry {
|
|||
return (meta.pc == null) ? null : meta.pc.pcNewInstance(sm, oid, clear);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the persistence-capable type for <code>type</code>. This might
|
||||
* be a generated subclass of <code>type</code>.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public static Class getPCType(Class type) {
|
||||
Meta meta = getMeta(type);
|
||||
return (meta.pc == null) ? null : meta.pc.getClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new identity object for the given
|
||||
* <code>PersistenceCapable</code> class.
|
||||
|
|
|
@ -18,17 +18,23 @@
|
|||
*/
|
||||
package org.apache.openjpa.enhance;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.JavaTypes;
|
||||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
||||
import org.apache.openjpa.kernel.OpenJPAStateManager;
|
||||
import org.apache.openjpa.kernel.StateManagerImpl;
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.meta.JavaTypes;
|
||||
import org.apache.openjpa.util.ApplicationIds;
|
||||
import org.apache.openjpa.util.ImplHelper;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
import org.apache.openjpa.util.ObjectId;
|
||||
import org.apache.openjpa.kernel.StateManagerImpl;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link PersistenceCapable} interface that can handle
|
||||
|
@ -38,12 +44,19 @@ import org.apache.openjpa.kernel.StateManagerImpl;
|
|||
* @since 1.0.0
|
||||
*/
|
||||
public class ReflectingPersistenceCapable
|
||||
implements PersistenceCapable, ManagedInstanceProvider {
|
||||
implements PersistenceCapable, ManagedInstanceProvider, Serializable {
|
||||
|
||||
private Object o;
|
||||
private StateManager sm;
|
||||
private PersistenceCapable pcSubclassInstance;
|
||||
private ClassMetaData meta;
|
||||
|
||||
// this will be reconstituted in readObject()
|
||||
private transient PersistenceCapable pcSubclassInstance;
|
||||
|
||||
// this will reconstituted by a call to pcReplaceStateManager() by the
|
||||
// instance that has a reference to the deserialized data
|
||||
private transient ClassMetaData meta;
|
||||
|
||||
private boolean serializationUserVisible = true;
|
||||
|
||||
public ReflectingPersistenceCapable(Object o, OpenJPAConfiguration conf) {
|
||||
this.o = o;
|
||||
|
@ -70,6 +83,8 @@ public class ReflectingPersistenceCapable
|
|||
|
||||
public void pcReplaceStateManager(StateManager sm) {
|
||||
this.sm = sm;
|
||||
if (meta == null && sm instanceof OpenJPAStateManager)
|
||||
meta = ((OpenJPAStateManager) sm).getMetaData();
|
||||
}
|
||||
|
||||
public void pcProvideField(int i) {
|
||||
|
@ -169,6 +184,10 @@ public class ReflectingPersistenceCapable
|
|||
}
|
||||
|
||||
public void pcCopyFields(Object fromObject, int[] fieldIndices) {
|
||||
if (fromObject instanceof ReflectingPersistenceCapable)
|
||||
fromObject = ((ReflectingPersistenceCapable) fromObject)
|
||||
.getManagedInstance();
|
||||
|
||||
for(int i = 0; i < fieldIndices.length; i++)
|
||||
pcCopyField(fromObject, fieldIndices[i]);
|
||||
}
|
||||
|
@ -305,21 +324,23 @@ public class ReflectingPersistenceCapable
|
|||
// ##### we can implement this if a state field has been set
|
||||
}
|
||||
|
||||
public void pcSetSerializationUserVisible(boolean userVisible) {
|
||||
serializationUserVisible = userVisible;
|
||||
}
|
||||
|
||||
public boolean pcIsSerializationUserVisible() {
|
||||
return serializationUserVisible;
|
||||
}
|
||||
|
||||
public Object getManagedInstance() {
|
||||
return o;
|
||||
}
|
||||
|
||||
private Object getValue(int i, Object o) {
|
||||
if (meta.getAccessType() == ClassMetaData.ACCESS_PROPERTY) {
|
||||
if (!meta.isIntercepting()) {
|
||||
Method meth = Reflection.findGetter(meta.getDescribedType(),
|
||||
meta.getField(i).getName(), true);
|
||||
return Reflection.get(o, meth);
|
||||
} else {
|
||||
Field field = Reflection.findField(meta.getDescribedType(),
|
||||
toFieldName(i), true);
|
||||
return Reflection.get(o, field);
|
||||
}
|
||||
Field field = Reflection.findField(meta.getDescribedType(),
|
||||
toFieldName(i), true);
|
||||
return Reflection.get(o, field);
|
||||
} else {
|
||||
Field field = (Field) meta.getField(i).getBackingMember();
|
||||
return Reflection.get(o, field);
|
||||
|
@ -350,4 +371,17 @@ public class ReflectingPersistenceCapable
|
|||
Reflection.set(o, field, val);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.defaultWriteObject();
|
||||
out.writeObject(meta.getDescribedType());
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws ClassNotFoundException, IOException {
|
||||
in.defaultReadObject();
|
||||
Class type = (Class) in.readObject();
|
||||
pcSubclassInstance = PCRegistry.newInstance(type, null, false);
|
||||
ImplHelper.registerPersistenceCapable(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.apache.openjpa.event;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
@ -44,7 +45,7 @@ import org.apache.openjpa.meta.MetaDataDefaults;
|
|||
* @nojavadoc
|
||||
*/
|
||||
public class LifecycleEventManager
|
||||
implements CallbackModes {
|
||||
implements CallbackModes, Serializable {
|
||||
|
||||
private static final Exception[] EMPTY_EXCEPTIONS = new Exception[0];
|
||||
|
||||
|
|
|
@ -19,16 +19,16 @@
|
|||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.Synchronization;
|
||||
import javax.transaction.Transaction;
|
||||
|
@ -41,23 +41,24 @@ import org.apache.openjpa.datacache.DataCacheStoreManager;
|
|||
import org.apache.openjpa.ee.ManagedRuntime;
|
||||
import org.apache.openjpa.enhance.PCRegistry;
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.apache.openjpa.event.RemoteCommitEventManager;
|
||||
import org.apache.openjpa.event.BrokerFactoryEvent;
|
||||
import org.apache.openjpa.event.RemoteCommitEventManager;
|
||||
import org.apache.openjpa.lib.conf.Configuration;
|
||||
import org.apache.openjpa.lib.conf.Configurations;
|
||||
import org.apache.openjpa.lib.log.Log;
|
||||
import org.apache.openjpa.lib.util.J2DoPrivHelper;
|
||||
import org.apache.openjpa.lib.util.JavaVersions;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.lib.util.ReferenceHashSet;
|
||||
import org.apache.openjpa.lib.util.JavaVersions;
|
||||
import org.apache.openjpa.lib.util.concurrent.ConcurrentHashMap;
|
||||
import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashSet;
|
||||
import org.apache.openjpa.lib.util.concurrent.ReentrantLock;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
import org.apache.openjpa.util.GeneralException;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
import org.apache.openjpa.util.InvalidStateException;
|
||||
import org.apache.openjpa.util.OpenJPAException;
|
||||
import org.apache.openjpa.util.UserException;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the {@link BrokerFactory}
|
||||
|
@ -114,11 +115,12 @@ public abstract class AbstractBrokerFactory
|
|||
|
||||
/**
|
||||
* Return an internal factory pool key for the given configuration.
|
||||
* We use the conf properties as given by the user because that is what's
|
||||
* passed to {@link #getPooledFactory} when looking for an existing factory.
|
||||
*/
|
||||
private static Map toPoolKey(OpenJPAConfiguration conf) {
|
||||
return conf.toProperties(false);
|
||||
private static Object toPoolKey(OpenJPAConfiguration conf) {
|
||||
if (conf.getId() != null)
|
||||
return conf.getId();
|
||||
else
|
||||
return conf.toProperties(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +128,18 @@ public abstract class AbstractBrokerFactory
|
|||
* if none.
|
||||
*/
|
||||
protected static AbstractBrokerFactory getPooledFactory(Map map) {
|
||||
return (AbstractBrokerFactory) _pool.get(map);
|
||||
Object key = Configurations.getProperty("Id", map);
|
||||
if (key == null)
|
||||
key = map;
|
||||
return getPooledFactoryForKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pooled factory matching the given key, or null
|
||||
* if none. The key must be of the form created by {@link #getPoolKey}.
|
||||
*/
|
||||
public static AbstractBrokerFactory getPooledFactoryForKey(Object key) {
|
||||
return (AbstractBrokerFactory) _pool.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,32 +187,9 @@ public abstract class AbstractBrokerFactory
|
|||
if (findExisting)
|
||||
broker = findBroker(user, pass, managed);
|
||||
if (broker == null) {
|
||||
// decorate the store manager for data caching and custom
|
||||
// result object providers; always make sure it's a delegating
|
||||
// store manager, because it's easier for users to deal with
|
||||
// that way
|
||||
StoreManager sm = newStoreManager();
|
||||
DelegatingStoreManager dsm = null;
|
||||
if (_conf.getDataCacheManagerInstance().getSystemDataCache()
|
||||
!= null)
|
||||
dsm = new DataCacheStoreManager(sm);
|
||||
dsm = new ROPStoreManager((dsm == null) ? sm : dsm);
|
||||
|
||||
broker = newBrokerImpl(user, pass);
|
||||
broker.initialize(this, dsm, managed, connRetainMode);
|
||||
addListeners(broker);
|
||||
|
||||
// if we're using remote events, register the event manager so
|
||||
// that it can broadcast commit notifications from the broker
|
||||
RemoteCommitEventManager remote = _conf.
|
||||
getRemoteCommitEventManager();
|
||||
if (remote.areRemoteEventsEnabled())
|
||||
broker.addTransactionListener(remote);
|
||||
|
||||
loadPersistentTypes(broker.getClassLoader());
|
||||
initializeBroker(managed, connRetainMode, broker, false);
|
||||
}
|
||||
_brokers.add(broker);
|
||||
_conf.setReadOnly(Configuration.INIT_STATE_FROZEN);
|
||||
return broker;
|
||||
} catch (OpenJPAException ke) {
|
||||
throw ke;
|
||||
|
@ -208,6 +198,39 @@ public abstract class AbstractBrokerFactory
|
|||
}
|
||||
}
|
||||
|
||||
void initializeBroker(boolean managed, int connRetainMode,
|
||||
BrokerImpl broker, boolean fromDeserialization) {
|
||||
assertOpen();
|
||||
makeReadOnly();
|
||||
|
||||
// decorate the store manager for data caching and custom
|
||||
// result object providers; always make sure it's a delegating
|
||||
// store manager, because it's easier for users to deal with
|
||||
// that way
|
||||
StoreManager sm = newStoreManager();
|
||||
DelegatingStoreManager dsm = null;
|
||||
if (_conf.getDataCacheManagerInstance().getSystemDataCache()
|
||||
!= null)
|
||||
dsm = new DataCacheStoreManager(sm);
|
||||
dsm = new ROPStoreManager((dsm == null) ? sm : dsm);
|
||||
|
||||
broker.initialize(this, dsm, managed, connRetainMode,
|
||||
fromDeserialization);
|
||||
if (!fromDeserialization)
|
||||
addListeners(broker);
|
||||
|
||||
// if we're using remote events, register the event manager so
|
||||
// that it can broadcast commit notifications from the broker
|
||||
RemoteCommitEventManager remote = _conf.
|
||||
getRemoteCommitEventManager();
|
||||
if (remote.areRemoteEventsEnabled())
|
||||
broker.addTransactionListener(remote);
|
||||
|
||||
loadPersistentTypes(broker.getClassLoader());
|
||||
_brokers.add(broker);
|
||||
_conf.setReadOnly(Configuration.INIT_STATE_FROZEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add factory-registered lifecycle listeners to the broker.
|
||||
*/
|
||||
|
@ -374,10 +397,10 @@ public abstract class AbstractBrokerFactory
|
|||
assertNoActiveTransaction();
|
||||
|
||||
// remove from factory pool
|
||||
Map map = toPoolKey(_conf);
|
||||
Object key = toPoolKey(_conf);
|
||||
synchronized (_pool) {
|
||||
if (_pool.get(map) == this)
|
||||
_pool.remove(map);
|
||||
if (_pool.get(key) == this)
|
||||
_pool.remove(key);
|
||||
}
|
||||
|
||||
// close all brokers
|
||||
|
@ -756,6 +779,15 @@ public abstract class AbstractBrokerFactory
|
|||
return Collections.unmodifiableCollection(_brokers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a key that can be used to obtain this broker factory from the
|
||||
* pool at a later time.
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public Object getPoolKey() {
|
||||
return toPoolKey(getConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple synchronization listener to remove completed transactions
|
||||
* from our cache.
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
|
@ -91,7 +94,7 @@ import org.apache.openjpa.util.UserException;
|
|||
* @author Abe White
|
||||
*/
|
||||
public class BrokerImpl
|
||||
implements Broker, FindCallbacks, Cloneable {
|
||||
implements Broker, FindCallbacks, Cloneable, Serializable {
|
||||
|
||||
/**
|
||||
* Incremental flush.
|
||||
|
@ -132,30 +135,35 @@ public class BrokerImpl
|
|||
private static final int FLAG_RETAINED_CONN = 2 << 10;
|
||||
private static final int FLAG_TRANS_ENDING = 2 << 11;
|
||||
|
||||
private static final Object[] EMPTY_OBJECTS = new Object[0];
|
||||
|
||||
private static final Localizer _loc =
|
||||
Localizer.forPackage(BrokerImpl.class);
|
||||
|
||||
// the store manager in use; this may be a decorator such as a
|
||||
// data cache store manager around the native store manager
|
||||
private DelegatingStoreManager _store = null;
|
||||
private transient DelegatingStoreManager _store = null;
|
||||
|
||||
// ref to producing factory and configuration
|
||||
private AbstractBrokerFactory _factory = null;
|
||||
private OpenJPAConfiguration _conf = null;
|
||||
private Compatibility _compat = null;
|
||||
private FetchConfiguration _fc = null;
|
||||
private Log _log = null;
|
||||
private String _user = null;
|
||||
private String _pass = null;
|
||||
private ManagedRuntime _runtime = null;
|
||||
private LockManager _lm = null;
|
||||
private InverseManager _im = null;
|
||||
private ReentrantLock _lock = null;
|
||||
private OpCallbacks _call = null;
|
||||
private RuntimeExceptionTranslator _extrans = null;
|
||||
|
||||
// these must be rebuilt by the facade layer during its deserialization
|
||||
private transient Log _log = null;
|
||||
private transient Compatibility _compat = null;
|
||||
private transient ManagedRuntime _runtime = null;
|
||||
private transient LockManager _lm = null;
|
||||
private transient InverseManager _im = null;
|
||||
private transient ReentrantLock _lock = null;
|
||||
private transient OpCallbacks _call = null;
|
||||
private transient RuntimeExceptionTranslator _extrans = null;
|
||||
|
||||
// ref to producing factory and configuration
|
||||
private transient AbstractBrokerFactory _factory = null;
|
||||
private transient OpenJPAConfiguration _conf = null;
|
||||
|
||||
// cache class loader associated with the broker
|
||||
private ClassLoader _loader = null;
|
||||
private transient ClassLoader _loader = null;
|
||||
|
||||
// user state
|
||||
private Synchronization _sync = null;
|
||||
|
@ -167,8 +175,11 @@ public class BrokerImpl
|
|||
private Set _transAdditions = null;
|
||||
private Set _derefCache = null;
|
||||
private Set _derefAdditions = null;
|
||||
private Map _loading = null;
|
||||
private Set _operating = null;
|
||||
|
||||
// these are used for method-internal state only
|
||||
private transient Map _loading = null;
|
||||
private transient Set _operating = null;
|
||||
|
||||
private Set _persistedClss = null;
|
||||
private Set _updatedClss = null;
|
||||
private Set _deletedClss = null;
|
||||
|
@ -179,14 +190,15 @@ public class BrokerImpl
|
|||
// (the first uses the transactional cache)
|
||||
private Set _savepointCache = null;
|
||||
private LinkedMap _savepoints = null;
|
||||
private SavepointManager _spm = null;
|
||||
private transient SavepointManager _spm = null;
|
||||
|
||||
// track open queries and extents so we can free their resources on close
|
||||
private ReferenceHashSet _queries = null;
|
||||
private ReferenceHashSet _extents = null;
|
||||
private transient ReferenceHashSet _queries = null;
|
||||
private transient ReferenceHashSet _extents = null;
|
||||
|
||||
// track operation stack depth
|
||||
private int _operationCount = 0;
|
||||
// track operation stack depth. Transient because operations cannot
|
||||
// span serialization.
|
||||
private transient int _operationCount = 0;
|
||||
|
||||
// options
|
||||
private boolean _nontransRead = false;
|
||||
|
@ -210,8 +222,13 @@ public class BrokerImpl
|
|||
|
||||
// status
|
||||
private int _flags = 0;
|
||||
private boolean _closed = false;
|
||||
private RuntimeException _closedException = null;
|
||||
|
||||
// this is not in status because it should not be serialized
|
||||
private transient boolean _isSerializing = false;
|
||||
|
||||
// transient because closed brokers can't be serialized
|
||||
private transient boolean _closed = false;
|
||||
private transient RuntimeException _closedException = null;
|
||||
|
||||
// event managers
|
||||
private TransactionEventManager _transEventManager = null;
|
||||
|
@ -219,8 +236,7 @@ public class BrokerImpl
|
|||
private LifecycleEventManager _lifeEventManager = null;
|
||||
private int _lifeCallbackMode = 0;
|
||||
|
||||
private boolean _initializeWasInvoked = false;
|
||||
private static final Object[] EMPTY_OBJECTS = new Object[0];
|
||||
private transient boolean _initializeWasInvoked = false;
|
||||
|
||||
/**
|
||||
* Set the persistence manager's authentication. This is the first
|
||||
|
@ -245,17 +261,22 @@ public class BrokerImpl
|
|||
* handle interaction with the data store
|
||||
* @param managed the transaction mode
|
||||
* @param connMode the connection retain mode
|
||||
* @param fromDeserialization whether this call happened because of a
|
||||
* deserialization or creation of a new BrokerImpl.
|
||||
*/
|
||||
public void initialize(AbstractBrokerFactory factory,
|
||||
DelegatingStoreManager sm, boolean managed, int connMode) {
|
||||
void initialize(AbstractBrokerFactory factory,
|
||||
DelegatingStoreManager sm, boolean managed, int connMode,
|
||||
boolean fromDeserialization) {
|
||||
_initializeWasInvoked = true;
|
||||
_loader = (ClassLoader) AccessController.doPrivileged(
|
||||
J2DoPrivHelper.getContextClassLoaderAction());
|
||||
_conf = factory.getConfiguration();
|
||||
if (!fromDeserialization)
|
||||
_conf = factory.getConfiguration();
|
||||
_compat = _conf.getCompatibilityInstance();
|
||||
_factory = factory;
|
||||
_log = _conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);
|
||||
_cache = new ManagedCache();
|
||||
if (!fromDeserialization)
|
||||
_cache = new ManagedCache(this);
|
||||
initializeOperatingSet();
|
||||
_connRetainMode = connMode;
|
||||
_managed = managed;
|
||||
|
@ -264,15 +285,17 @@ public class BrokerImpl
|
|||
else
|
||||
_runtime = new LocalManagedRuntime(this);
|
||||
|
||||
_lifeEventManager = new LifecycleEventManager();
|
||||
_transEventManager = new TransactionEventManager();
|
||||
int cmode = _conf.getMetaDataRepositoryInstance().
|
||||
getMetaDataFactory().getDefaults().getCallbackMode();
|
||||
setLifecycleListenerCallbackMode(cmode);
|
||||
setTransactionListenerCallbackMode(cmode);
|
||||
if (!fromDeserialization) {
|
||||
_lifeEventManager = new LifecycleEventManager();
|
||||
_transEventManager = new TransactionEventManager();
|
||||
int cmode = _conf.getMetaDataRepositoryInstance().
|
||||
getMetaDataFactory().getDefaults().getCallbackMode();
|
||||
setLifecycleListenerCallbackMode(cmode);
|
||||
setTransactionListenerCallbackMode(cmode);
|
||||
|
||||
// setup default options
|
||||
_factory.configureBroker(this);
|
||||
// setup default options
|
||||
_factory.configureBroker(this);
|
||||
}
|
||||
|
||||
// make sure to do this after configuring broker so that store manager
|
||||
// can look to broker configuration; we set both store and lock managers
|
||||
|
@ -287,8 +310,10 @@ public class BrokerImpl
|
|||
|
||||
if (_connRetainMode == CONN_RETAIN_ALWAYS)
|
||||
retainConnection();
|
||||
_fc = _store.newFetchConfiguration();
|
||||
_fc.setContext(this);
|
||||
if (!fromDeserialization) {
|
||||
_fc = _store.newFetchConfiguration();
|
||||
_fc.setContext(this);
|
||||
}
|
||||
|
||||
// synch with the global transaction in progress, if any
|
||||
if (_factory.syncWithManagedTransaction(this, false))
|
||||
|
@ -749,7 +774,7 @@ public class BrokerImpl
|
|||
|
||||
// cached instance?
|
||||
StateManagerImpl sm = getStateManagerImplById(oid,
|
||||
(flags & OID_ALLOW_NEW) != 0 || (_flags & FLAG_FLUSHED) != 0);
|
||||
(flags & OID_ALLOW_NEW) != 0 || hasFlushed());
|
||||
if (sm != null) {
|
||||
if (!requiresLoad(sm, true, fetch, edata, flags))
|
||||
return call.processReturn(oid, sm);
|
||||
|
@ -911,7 +936,7 @@ public class BrokerImpl
|
|||
// if we don't have a cached instance or it is not transactional
|
||||
// and is hollow or we need to validate, load it
|
||||
sm = getStateManagerImplById(oid, (flags & OID_ALLOW_NEW) != 0
|
||||
|| (_flags & FLAG_FLUSHED) != 0);
|
||||
|| hasFlushed());
|
||||
initialized = sm != null;
|
||||
if (!initialized)
|
||||
sm = newStateManagerImpl(oid, (flags & OID_COPY) != 0);
|
||||
|
@ -986,6 +1011,10 @@ public class BrokerImpl
|
|||
}
|
||||
}
|
||||
|
||||
private boolean hasFlushed() {
|
||||
return (_flags & FLAG_FLUSHED) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given instance needs loading before being returned
|
||||
* to the user.
|
||||
|
@ -1457,8 +1486,7 @@ public class BrokerImpl
|
|||
if (_savepoints != null && _savepoints.containsKey(name))
|
||||
throw new UserException(_loc.get("savepoint-exists", name));
|
||||
|
||||
if ((_flags & FLAG_FLUSHED) != 0
|
||||
&& !_spm.supportsIncrementalFlush())
|
||||
if (hasFlushed() && !_spm.supportsIncrementalFlush())
|
||||
throw new UnsupportedException(_loc.get
|
||||
("savepoint-flush-not-supported"));
|
||||
|
||||
|
@ -2359,8 +2387,7 @@ public class BrokerImpl
|
|||
|
||||
// an embedded field; notify the owner that the value has
|
||||
// changed by becoming independently persistent
|
||||
sm.getOwner().dirty(sm.getOwnerMetaData().
|
||||
getFieldMetaData().getIndex());
|
||||
sm.getOwner().dirty(sm.getOwnerIndex());
|
||||
_cache.persist(sm);
|
||||
pc = sm.getPersistenceCapable();
|
||||
} else {
|
||||
|
@ -4357,278 +4384,69 @@ public class BrokerImpl
|
|||
return (sm == null) ? null : sm.getManagedInstance();
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
assertOpen();
|
||||
lock();
|
||||
try {
|
||||
if (isActive()) {
|
||||
if (!getOptimistic())
|
||||
throw new InvalidStateException(
|
||||
_loc.get("cant-serialize-pessimistic-broker"));
|
||||
if (hasFlushed())
|
||||
throw new InvalidStateException(
|
||||
_loc.get("cant-serialize-flushed-broker"));
|
||||
if (hasConnection())
|
||||
throw new InvalidStateException(
|
||||
_loc.get("cant-serialize-connected-broker"));
|
||||
}
|
||||
|
||||
try {
|
||||
_isSerializing = true;
|
||||
out.writeObject(_factory.getPoolKey());
|
||||
out.defaultWriteObject();
|
||||
} finally {
|
||||
_isSerializing = false;
|
||||
}
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws ClassNotFoundException, IOException {
|
||||
Object factoryKey = in.readObject();
|
||||
AbstractBrokerFactory factory =
|
||||
AbstractBrokerFactory.getPooledFactoryForKey(factoryKey);
|
||||
|
||||
// this needs to happen before defaultReadObject so that it's
|
||||
// available for calls to broker.getConfiguration() during
|
||||
// StateManager deserialization
|
||||
_conf = factory.getConfiguration();
|
||||
|
||||
in.defaultReadObject();
|
||||
factory.initializeBroker(_managed, _connRetainMode, this, true);
|
||||
|
||||
// re-initialize the lock if needed.
|
||||
setMultithreaded(_multithreaded);
|
||||
|
||||
if (isActive() && _runtime instanceof LocalManagedRuntime)
|
||||
((LocalManagedRuntime) _runtime).begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache of managed objects.
|
||||
* Whether or not this broker is in the midst of being serialized.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
private class ManagedCache {
|
||||
|
||||
private Map _main; // oid -> sm
|
||||
private Map _conflicts = null; // conflict oid -> new sm
|
||||
private Map _news = null; // tmp id -> new sm
|
||||
private Collection _embeds = null; // embedded/non-persistent sms
|
||||
private Collection _untracked = null; // hard refs to untracked sms
|
||||
|
||||
/**
|
||||
* Constructor; supply primary cache map.
|
||||
*/
|
||||
private ManagedCache() {
|
||||
_main = newManagedObjectCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the instance for the given oid, optionally allowing
|
||||
* new instances.
|
||||
*/
|
||||
public StateManagerImpl getById(Object oid, boolean allowNew) {
|
||||
if (oid == null)
|
||||
return null;
|
||||
|
||||
// check main cache for oid
|
||||
StateManagerImpl sm = (StateManagerImpl) _main.get(oid);
|
||||
StateManagerImpl sm2;
|
||||
if (sm != null) {
|
||||
// if it's a new instance, we know it's the only match, because
|
||||
// other pers instances override new instances in _cache
|
||||
if (sm.isNew())
|
||||
return (allowNew) ? sm : null;
|
||||
if (!allowNew || !sm.isDeleted())
|
||||
return sm;
|
||||
|
||||
// sm is deleted; check conflict cache
|
||||
if (_conflicts != null) {
|
||||
sm2 = (StateManagerImpl) _conflicts.get(oid);
|
||||
if (sm2 != null)
|
||||
return sm2;
|
||||
}
|
||||
}
|
||||
|
||||
// at this point sm is null or deleted; check the new cache for
|
||||
// any matches. this allows us to match app id objects to new
|
||||
// instances without permanant oids
|
||||
if (allowNew && _news != null && !_news.isEmpty()) {
|
||||
sm2 = (StateManagerImpl) _news.get(oid);
|
||||
if (sm2 != null)
|
||||
return sm2;
|
||||
}
|
||||
return sm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when a new state manager initializes itself.
|
||||
*/
|
||||
public void add(StateManagerImpl sm) {
|
||||
if (!sm.isIntercepting()) {
|
||||
if (_untracked == null)
|
||||
_untracked = new HashSet();
|
||||
_untracked.add(sm);
|
||||
}
|
||||
|
||||
if (!sm.isPersistent() || sm.isEmbedded()) {
|
||||
if (_embeds == null)
|
||||
_embeds = new ReferenceHashSet(ReferenceHashSet.WEAK);
|
||||
_embeds.add(sm);
|
||||
return;
|
||||
}
|
||||
|
||||
// initializing new instance; put in new cache because won't have
|
||||
// permanent oid yet
|
||||
if (sm.isNew()) {
|
||||
if (_news == null)
|
||||
_news = new HashMap();
|
||||
_news.put(sm.getId(), sm);
|
||||
return;
|
||||
}
|
||||
|
||||
// initializing persistent instance; put in main cache
|
||||
StateManagerImpl orig = (StateManagerImpl) _main.put
|
||||
(sm.getObjectId(), sm);
|
||||
if (orig != null) {
|
||||
_main.put(sm.getObjectId(), orig);
|
||||
throw new UserException(_loc.get("dup-load",
|
||||
sm.getObjectId(), Exceptions.toString
|
||||
(orig.getManagedInstance()))).
|
||||
setFailedObject(sm.getManagedInstance());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given state manager from the cache when it transitions
|
||||
* to transient.
|
||||
*/
|
||||
public void remove(Object id, StateManagerImpl sm) {
|
||||
// if it has a permanent oid, remove from main / conflict cache,
|
||||
// else remove from embedded/nontrans cache, and if not there
|
||||
// remove from new cache
|
||||
Object orig;
|
||||
if (sm.getObjectId() != null) {
|
||||
orig = _main.remove(id);
|
||||
if (orig != sm) {
|
||||
if (orig != null)
|
||||
_main.put(id, orig); // put back
|
||||
if (_conflicts != null) {
|
||||
orig = _conflicts.remove(id);
|
||||
if (orig != null && orig != sm)
|
||||
_conflicts.put(id, orig); // put back
|
||||
}
|
||||
}
|
||||
} else if ((_embeds == null || !_embeds.remove(sm))
|
||||
&& _news != null) {
|
||||
orig = _news.remove(id);
|
||||
if (orig != null && orig != sm)
|
||||
_news.put(id, orig); // put back
|
||||
}
|
||||
|
||||
if (_untracked != null)
|
||||
_untracked.remove(sm);
|
||||
}
|
||||
|
||||
/**
|
||||
* An embedded or nonpersistent managed instance has been persisted.
|
||||
*/
|
||||
public void persist(StateManagerImpl sm) {
|
||||
if (_embeds != null)
|
||||
_embeds.remove(sm);
|
||||
}
|
||||
|
||||
/**
|
||||
* A new instance has just been assigned a permanent oid.
|
||||
*/
|
||||
public void assignObjectId(Object id, StateManagerImpl sm) {
|
||||
// if assigning oid, remove from new cache and put in primary; may
|
||||
// not be in new cache if another new instance had same id
|
||||
StateManagerImpl orig = (StateManagerImpl) _news.remove(id);
|
||||
if (orig != null && orig != sm)
|
||||
_news.put(id, orig); // put back
|
||||
|
||||
// put in main cache, but make sure we don't replace another
|
||||
// instance with the same oid
|
||||
orig = (StateManagerImpl) _main.put(sm.getObjectId(), sm);
|
||||
if (orig != null) {
|
||||
_main.put(sm.getObjectId(), orig);
|
||||
if (!orig.isDeleted())
|
||||
throw new UserException(_loc.get("dup-oid-assign",
|
||||
sm.getObjectId(), Exceptions.toString
|
||||
(sm.getManagedInstance()))).
|
||||
setFailedObject(sm.getManagedInstance());
|
||||
|
||||
// same oid as deleted instance; put in conflict cache
|
||||
if (_conflicts == null)
|
||||
_conflicts = new HashMap();
|
||||
_conflicts.put(sm.getObjectId(), sm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A new instance has committed; recache under permanent oid.
|
||||
*/
|
||||
public void commitNew(Object id, StateManagerImpl sm) {
|
||||
// if the id didn't change, the instance was already assigned an
|
||||
// id, but it could have been in conflict cache
|
||||
StateManagerImpl orig;
|
||||
if (sm.getObjectId() == id) {
|
||||
orig = (_conflicts == null) ? null
|
||||
: (StateManagerImpl) _conflicts.remove(id);
|
||||
if (orig == sm) {
|
||||
orig = (StateManagerImpl) _main.put(id, sm);
|
||||
if (orig != null && !orig.isDeleted()) {
|
||||
_main.put(sm.getObjectId(), orig);
|
||||
throw new UserException(_loc.get("dup-oid-assign",
|
||||
sm.getObjectId(), Exceptions.toString
|
||||
(sm.getManagedInstance()))).setFailedObject
|
||||
(sm.getManagedInstance()).setFatal(true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// oid changed, so it must previously have been a new instance
|
||||
// without an assigned oid. remove it from the new cache; ok if
|
||||
// we end up removing another instance with same id
|
||||
if (_news != null)
|
||||
_news.remove(id);
|
||||
|
||||
// and put into main cache now that id is asssigned
|
||||
orig = (StateManagerImpl) _main.put(sm.getObjectId(), sm);
|
||||
if (orig != null && orig != sm && !orig.isDeleted()) {
|
||||
// put back orig and throw error
|
||||
_main.put(sm.getObjectId(), orig);
|
||||
throw new UserException(_loc.get("dup-oid-assign",
|
||||
sm.getObjectId(), Exceptions.toString
|
||||
(sm.getManagedInstance()))).setFailedObject
|
||||
(sm.getManagedInstance()).setFatal(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of all cached persistent objects.
|
||||
*/
|
||||
public Collection copy() {
|
||||
// proxies not included here because the state manager is always
|
||||
// present in other caches too
|
||||
|
||||
int size = _main.size();
|
||||
if (_conflicts != null)
|
||||
size += _conflicts.size();
|
||||
if (_news != null)
|
||||
size += _news.size();
|
||||
if (_embeds != null)
|
||||
size += _embeds.size();
|
||||
if (size == 0)
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
List copy = new ArrayList(size);
|
||||
for (Iterator itr = _main.values().iterator(); itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
if (_conflicts != null && !_conflicts.isEmpty())
|
||||
for (Iterator itr = _conflicts.values().iterator();
|
||||
itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
if (_news != null && !_news.isEmpty())
|
||||
for (Iterator itr = _news.values().iterator(); itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
if (_embeds != null && !_embeds.isEmpty())
|
||||
for (Iterator itr = _embeds.iterator(); itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
public void clear() {
|
||||
_main = newManagedObjectCache();
|
||||
if (_conflicts != null)
|
||||
_conflicts = null;
|
||||
if (_news != null)
|
||||
_news = null;
|
||||
if (_embeds != null)
|
||||
_embeds = null;
|
||||
if (_untracked != null)
|
||||
_untracked = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear new instances without permanent oids.
|
||||
*/
|
||||
public void clearNew() {
|
||||
if (_news != null)
|
||||
_news = null;
|
||||
}
|
||||
|
||||
private void dirtyCheck() {
|
||||
if (_untracked == null)
|
||||
return;
|
||||
|
||||
for (Iterator iter = _untracked.iterator(); iter.hasNext(); )
|
||||
((StateManagerImpl) iter.next()).dirtyCheck();
|
||||
}
|
||||
boolean isSerializing() {
|
||||
return _isSerializing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transactional cache that holds soft refs to clean instances.
|
||||
*/
|
||||
private static class TransactionalCache
|
||||
implements Set {
|
||||
static class TransactionalCache
|
||||
implements Set, Serializable {
|
||||
|
||||
private final boolean _orderDirty;
|
||||
private Set _dirty = null;
|
||||
|
|
|
@ -171,8 +171,7 @@ class DetachedStateAttachStrategy
|
|||
BitSet toLoad = (BitSet) fields.clone();
|
||||
toLoad.andNot(sm.getLoaded()); // skip already loaded fields
|
||||
if (toLoad.length() > 0)
|
||||
sm.loadFields(toLoad, null, LockLevels.LOCK_NONE, null,
|
||||
false);
|
||||
sm.loadFields(toLoad, null, LockLevels.LOCK_NONE, null);
|
||||
//### we should calculate lock level above
|
||||
}
|
||||
Object version = state[offset];
|
||||
|
|
|
@ -145,7 +145,7 @@ public class DetachedStateManager
|
|||
}
|
||||
}
|
||||
FetchConfiguration fc = broker.getFetchConfiguration();
|
||||
sm.loadFields(load, fc, fc.getWriteLockLevel(), null, true);
|
||||
sm.loadFields(load, fc, fc.getWriteLockLevel(), null);
|
||||
}
|
||||
Object origVersion = sm.getVersion();
|
||||
sm.setVersion(_version);
|
||||
|
@ -698,7 +698,7 @@ public class DetachedStateManager
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ValueMetaData getOwnerMetaData() {
|
||||
public int getOwnerIndex() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -88,8 +88,8 @@ public class DetachedValueStateManager
|
|||
return null;
|
||||
}
|
||||
|
||||
public ValueMetaData getOwnerMetaData() {
|
||||
return null;
|
||||
public int getOwnerIndex() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean isEmbedded() {
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.lib.util.ReferenceHashSet;
|
||||
import org.apache.openjpa.util.Exceptions;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
import org.apache.openjpa.util.UserException;
|
||||
|
||||
/**
|
||||
* Cache of managed objects. Must be static for serialization reasons.
|
||||
*/
|
||||
class ManagedCache implements Serializable {
|
||||
|
||||
private static final Localizer _loc =
|
||||
Localizer.forPackage(ManagedCache.class);
|
||||
|
||||
private Map _main; // oid -> sm
|
||||
private Map _conflicts = null; // conflict oid -> new sm
|
||||
private Map _news = null; // tmp id -> new sm
|
||||
private Collection _embeds = null; // embedded/non-persistent sms
|
||||
private Collection _untracked = null; // hard refs to untracked sms
|
||||
private BrokerImpl broker;
|
||||
|
||||
/**
|
||||
* Constructor; supply primary cache map.
|
||||
*/
|
||||
ManagedCache(BrokerImpl broker) {
|
||||
this.broker = broker;
|
||||
_main = broker.newManagedObjectCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the instance for the given oid, optionally allowing
|
||||
* new instances.
|
||||
*/
|
||||
public StateManagerImpl getById(Object oid, boolean allowNew) {
|
||||
if (oid == null)
|
||||
return null;
|
||||
|
||||
// check main cache for oid
|
||||
StateManagerImpl sm = (StateManagerImpl) _main.get(oid);
|
||||
StateManagerImpl sm2;
|
||||
if (sm != null) {
|
||||
// if it's a new instance, we know it's the only match, because
|
||||
// other pers instances override new instances in _cache
|
||||
if (sm.isNew())
|
||||
return (allowNew) ? sm : null;
|
||||
if (!allowNew || !sm.isDeleted())
|
||||
return sm;
|
||||
|
||||
// sm is deleted; check conflict cache
|
||||
if (_conflicts != null) {
|
||||
sm2 = (StateManagerImpl) _conflicts.get(oid);
|
||||
if (sm2 != null)
|
||||
return sm2;
|
||||
}
|
||||
}
|
||||
|
||||
// at this point sm is null or deleted; check the new cache for
|
||||
// any matches. this allows us to match app id objects to new
|
||||
// instances without permanant oids
|
||||
if (allowNew && _news != null && !_news.isEmpty()) {
|
||||
sm2 = (StateManagerImpl) _news.get(oid);
|
||||
if (sm2 != null)
|
||||
return sm2;
|
||||
}
|
||||
return sm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when a new state manager initializes itself.
|
||||
*/
|
||||
public void add(StateManagerImpl sm) {
|
||||
if (!sm.isIntercepting()) {
|
||||
if (_untracked == null)
|
||||
_untracked = new HashSet();
|
||||
_untracked.add(sm);
|
||||
}
|
||||
|
||||
if (!sm.isPersistent() || sm.isEmbedded()) {
|
||||
if (_embeds == null)
|
||||
_embeds = new ReferenceHashSet(ReferenceHashSet.WEAK);
|
||||
_embeds.add(sm);
|
||||
return;
|
||||
}
|
||||
|
||||
// initializing new instance; put in new cache because won't have
|
||||
// permanent oid yet
|
||||
if (sm.isNew()) {
|
||||
if (_news == null)
|
||||
_news = new HashMap();
|
||||
_news.put(sm.getId(), sm);
|
||||
return;
|
||||
}
|
||||
|
||||
// initializing persistent instance; put in main cache
|
||||
StateManagerImpl orig = (StateManagerImpl) _main.put
|
||||
(sm.getObjectId(), sm);
|
||||
if (orig != null) {
|
||||
_main.put(sm.getObjectId(), orig);
|
||||
throw new UserException(_loc.get("dup-load", sm.getObjectId(),
|
||||
Exceptions.toString(orig.getManagedInstance())))
|
||||
.setFailedObject(sm.getManagedInstance());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given state manager from the cache when it transitions
|
||||
* to transient.
|
||||
*/
|
||||
public void remove(Object id, StateManagerImpl sm) {
|
||||
// if it has a permanent oid, remove from main / conflict cache,
|
||||
// else remove from embedded/nontrans cache, and if not there
|
||||
// remove from new cache
|
||||
Object orig;
|
||||
if (sm.getObjectId() != null) {
|
||||
orig = _main.remove(id);
|
||||
if (orig != sm) {
|
||||
if (orig != null)
|
||||
_main.put(id, orig); // put back
|
||||
if (_conflicts != null) {
|
||||
orig = _conflicts.remove(id);
|
||||
if (orig != null && orig != sm)
|
||||
_conflicts.put(id, orig); // put back
|
||||
}
|
||||
}
|
||||
} else if ((_embeds == null || !_embeds.remove(sm))
|
||||
&& _news != null) {
|
||||
orig = _news.remove(id);
|
||||
if (orig != null && orig != sm)
|
||||
_news.put(id, orig); // put back
|
||||
}
|
||||
|
||||
if (_untracked != null)
|
||||
_untracked.remove(sm);
|
||||
}
|
||||
|
||||
/**
|
||||
* An embedded or nonpersistent managed instance has been persisted.
|
||||
*/
|
||||
public void persist(StateManagerImpl sm) {
|
||||
if (_embeds != null)
|
||||
_embeds.remove(sm);
|
||||
}
|
||||
|
||||
/**
|
||||
* A new instance has just been assigned a permanent oid.
|
||||
*/
|
||||
public void assignObjectId(Object id, StateManagerImpl sm) {
|
||||
// if assigning oid, remove from new cache and put in primary; may
|
||||
// not be in new cache if another new instance had same id
|
||||
StateManagerImpl orig = null;
|
||||
if (_news != null) {
|
||||
orig = (StateManagerImpl) _news.remove(id);
|
||||
if (orig != null && orig != sm)
|
||||
_news.put(id, orig); // put back
|
||||
}
|
||||
|
||||
// put in main cache, but make sure we don't replace another
|
||||
// instance with the same oid
|
||||
orig = (StateManagerImpl) _main.put(sm.getObjectId(), sm);
|
||||
if (orig != null) {
|
||||
_main.put(sm.getObjectId(), orig);
|
||||
if (!orig.isDeleted())
|
||||
throw new UserException(_loc.get("dup-oid-assign",
|
||||
sm.getObjectId(),
|
||||
Exceptions.toString(sm.getManagedInstance())))
|
||||
.setFailedObject(sm.getManagedInstance());
|
||||
|
||||
// same oid as deleted instance; put in conflict cache
|
||||
if (_conflicts == null)
|
||||
_conflicts = new HashMap();
|
||||
_conflicts.put(sm.getObjectId(), sm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A new instance has committed; recache under permanent oid.
|
||||
*/
|
||||
public void commitNew(Object id, StateManagerImpl sm) {
|
||||
// if the id didn't change, the instance was already assigned an
|
||||
// id, but it could have been in conflict cache
|
||||
StateManagerImpl orig;
|
||||
if (sm.getObjectId() == id) {
|
||||
orig = (_conflicts == null) ? null
|
||||
: (StateManagerImpl) _conflicts.remove(id);
|
||||
if (orig == sm) {
|
||||
orig = (StateManagerImpl) _main.put(id, sm);
|
||||
if (orig != null && !orig.isDeleted()) {
|
||||
_main.put(sm.getObjectId(), orig);
|
||||
throw new UserException(_loc.get("dup-oid-assign",
|
||||
sm.getObjectId(), Exceptions.toString(
|
||||
sm.getManagedInstance())))
|
||||
.setFailedObject(sm.getManagedInstance())
|
||||
.setFatal(true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// oid changed, so it must previously have been a new instance
|
||||
// without an assigned oid. remove it from the new cache; ok if
|
||||
// we end up removing another instance with same id
|
||||
if (_news != null)
|
||||
_news.remove(id);
|
||||
|
||||
// and put into main cache now that id is asssigned
|
||||
orig = (StateManagerImpl) _main.put(sm.getObjectId(), sm);
|
||||
if (orig != null && orig != sm && !orig.isDeleted()) {
|
||||
// put back orig and throw error
|
||||
_main.put(sm.getObjectId(), orig);
|
||||
throw new UserException(_loc.get("dup-oid-assign",
|
||||
sm.getObjectId(), Exceptions.toString(sm.getManagedInstance())))
|
||||
.setFailedObject(sm.getManagedInstance()).setFatal(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of all cached persistent objects.
|
||||
*/
|
||||
public Collection copy() {
|
||||
// proxies not included here because the state manager is always
|
||||
// present in other caches too
|
||||
|
||||
int size = _main.size();
|
||||
if (_conflicts != null)
|
||||
size += _conflicts.size();
|
||||
if (_news != null)
|
||||
size += _news.size();
|
||||
if (_embeds != null)
|
||||
size += _embeds.size();
|
||||
if (size == 0)
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
List copy = new ArrayList(size);
|
||||
for (Iterator itr = _main.values().iterator(); itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
if (_conflicts != null && !_conflicts.isEmpty())
|
||||
for (Iterator itr = _conflicts.values().iterator();
|
||||
itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
if (_news != null && !_news.isEmpty())
|
||||
for (Iterator itr = _news.values().iterator(); itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
if (_embeds != null && !_embeds.isEmpty())
|
||||
for (Iterator itr = _embeds.iterator(); itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
public void clear() {
|
||||
_main = broker.newManagedObjectCache();
|
||||
if (_conflicts != null)
|
||||
_conflicts = null;
|
||||
if (_news != null)
|
||||
_news = null;
|
||||
if (_embeds != null)
|
||||
_embeds = null;
|
||||
if (_untracked != null)
|
||||
_untracked = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear new instances without permanent oids.
|
||||
*/
|
||||
public void clearNew() {
|
||||
if (_news != null)
|
||||
_news = null;
|
||||
}
|
||||
|
||||
void dirtyCheck() {
|
||||
if (_untracked == null)
|
||||
return;
|
||||
|
||||
for (Iterator iter = _untracked.iterator(); iter.hasNext(); )
|
||||
((StateManagerImpl) iter.next()).dirtyCheck();
|
||||
}
|
||||
}
|
|
@ -309,8 +309,8 @@ public class ObjectIdStateManager
|
|||
return _owner;
|
||||
}
|
||||
|
||||
public ValueMetaData getOwnerMetaData() {
|
||||
return _vmd;
|
||||
public int getOwnerIndex() {
|
||||
return _vmd.getFieldMetaData().getIndex();
|
||||
}
|
||||
|
||||
public boolean isEmbedded() {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
@ -30,7 +31,7 @@ import java.util.Map;
|
|||
* @author Steve Kim
|
||||
* @since 0.3.4
|
||||
*/
|
||||
public class OpenJPASavepoint {
|
||||
public class OpenJPASavepoint implements Serializable {
|
||||
|
||||
private final Broker _broker;
|
||||
private final String _name;
|
||||
|
|
|
@ -102,9 +102,11 @@ public interface OpenJPAStateManager
|
|||
public OpenJPAStateManager getOwner();
|
||||
|
||||
/**
|
||||
* Return the owning value.
|
||||
* Return the owning value's field index
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public ValueMetaData getOwnerMetaData();
|
||||
public int getOwnerIndex();
|
||||
|
||||
/**
|
||||
* Return true if this instance has an owner, meaning it is an embedded
|
||||
|
|
|
@ -18,13 +18,16 @@
|
|||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.apache.openjpa.enhance.Reflection;
|
||||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.meta.JavaTypes;
|
||||
import org.apache.openjpa.util.ProxyManager;
|
||||
|
@ -35,13 +38,14 @@ import org.apache.openjpa.util.ProxyManager;
|
|||
* @author Abe White
|
||||
*/
|
||||
public class SaveFieldManager
|
||||
extends ClearFieldManager {
|
||||
extends ClearFieldManager
|
||||
implements Serializable {
|
||||
|
||||
private final StateManagerImpl _sm;
|
||||
private final BitSet _unloaded;
|
||||
private BitSet _saved = null;
|
||||
private int[] _copyField = null;
|
||||
private PersistenceCapable _state = null;
|
||||
private transient PersistenceCapable _state = null;
|
||||
|
||||
// used to track field value during store/fetch cycle
|
||||
private Object _field = null;
|
||||
|
@ -140,7 +144,7 @@ public class SaveFieldManager
|
|||
if (_copyField == null)
|
||||
_copyField = new int[1];
|
||||
_copyField[0] = field;
|
||||
_state.pcCopyFields(_sm.getPersistenceCapable(), _copyField);
|
||||
getState().pcCopyFields(_sm.getPersistenceCapable(), _copyField);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -164,7 +168,7 @@ public class SaveFieldManager
|
|||
if (_copyField == null)
|
||||
_copyField = new int[1];
|
||||
_copyField[0] = field;
|
||||
_sm.getPersistenceCapable().pcCopyFields(_state, _copyField);
|
||||
_sm.getPersistenceCapable().pcCopyFields(getState(), _copyField);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -177,12 +181,12 @@ public class SaveFieldManager
|
|||
// if the field is not available, assume that it has changed.
|
||||
if (_saved == null || !_saved.get(field))
|
||||
return false;
|
||||
if (!(_state.pcGetStateManager() instanceof StateManagerImpl))
|
||||
if (!(getState().pcGetStateManager() instanceof StateManagerImpl))
|
||||
return false;
|
||||
|
||||
StateManagerImpl sm = (StateManagerImpl) _state.pcGetStateManager();
|
||||
StateManagerImpl sm = (StateManagerImpl) getState().pcGetStateManager();
|
||||
SingleFieldManager single = new SingleFieldManager(sm, sm.getBroker());
|
||||
sm.provideField(_state, single, field);
|
||||
sm.provideField(getState(), single, field);
|
||||
Object old = single.fetchObjectField(field);
|
||||
return current == old || current != null && current.equals(old);
|
||||
}
|
||||
|
@ -227,4 +231,15 @@ public class SaveFieldManager
|
|||
_saved.clear(field);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
oos.defaultWriteObject();
|
||||
_sm.writePC(oos, _state);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois)
|
||||
throws IOException, ClassNotFoundException {
|
||||
ois.defaultReadObject();
|
||||
_state = _sm.readPC(ois);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
@ -37,7 +41,8 @@ import org.apache.openjpa.util.ProxyManager;
|
|||
* @since 0.3.4
|
||||
*/
|
||||
class SavepointFieldManager
|
||||
extends ClearFieldManager {
|
||||
extends ClearFieldManager
|
||||
implements Serializable {
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
(SavepointFieldManager.class);
|
||||
|
@ -47,7 +52,7 @@ class SavepointFieldManager
|
|||
private final BitSet _dirty;
|
||||
private final BitSet _flush;
|
||||
private final PCState _state;
|
||||
private PersistenceCapable _copy;
|
||||
private transient PersistenceCapable _copy;
|
||||
|
||||
private final Object _version;
|
||||
private final Object _loadVersion;
|
||||
|
@ -227,4 +232,15 @@ class SavepointFieldManager
|
|||
if (curVal != null && _field == null)
|
||||
throw new InternalException(_loc.get("no-savepoint-copy", fmd));
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
oos.defaultWriteObject();
|
||||
_sm.writePC(oos, _copy);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois)
|
||||
throws IOException, ClassNotFoundException {
|
||||
ois.defaultReadObject();
|
||||
_copy = _sm.readPC(ois);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.openjpa.kernel;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
|
@ -50,7 +51,8 @@ import org.apache.openjpa.util.UserException;
|
|||
* @author Abe White
|
||||
*/
|
||||
class SingleFieldManager
|
||||
extends TransferFieldManager {
|
||||
extends TransferFieldManager
|
||||
implements Serializable {
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
(SingleFieldManager.class);
|
||||
|
@ -235,7 +237,7 @@ class SingleFieldManager
|
|||
|
||||
StateManagerImpl sm = _broker.getStateManagerImpl(obj, false);
|
||||
if (sm != null && sm.getOwner() == _sm
|
||||
&& sm.getOwnerMetaData() == vmd)
|
||||
&& sm.getOwnerIndex() == vmd.getFieldMetaData().getIndex())
|
||||
sm.release(true);
|
||||
}
|
||||
|
||||
|
@ -380,7 +382,8 @@ class SingleFieldManager
|
|||
// delete if unknowned or this isn't an embedded field or if owned by us
|
||||
StateManagerImpl sm = _broker.getStateManagerImpl(obj, false);
|
||||
if (sm != null && (sm.getOwner() == null || !vmd.isEmbeddedPC()
|
||||
|| (sm.getOwner() == _sm && sm.getOwnerMetaData() == vmd)))
|
||||
|| (sm.getOwner() == _sm
|
||||
&& sm.getOwnerIndex() == vmd.getFieldMetaData().getIndex())))
|
||||
_broker.delete(sm.getManagedInstance(), sm, call);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -77,7 +81,7 @@ import serp.util.Numbers;
|
|||
* @author Abe White
|
||||
*/
|
||||
public class StateManagerImpl
|
||||
implements OpenJPAStateManager {
|
||||
implements OpenJPAStateManager, Serializable {
|
||||
|
||||
public static final int LOAD_FGS = 0;
|
||||
public static final int LOAD_ALL = 1;
|
||||
|
@ -105,8 +109,8 @@ public class StateManagerImpl
|
|||
(StateManagerImpl.class);
|
||||
|
||||
// information about the instance
|
||||
private PersistenceCapable _pc = null;
|
||||
private ClassMetaData _meta = null;
|
||||
private transient PersistenceCapable _pc = null;
|
||||
private transient ClassMetaData _meta = null;
|
||||
private BitSet _loaded = null;
|
||||
private BitSet _dirty = null;
|
||||
private BitSet _flush = null;
|
||||
|
@ -121,7 +125,7 @@ public class StateManagerImpl
|
|||
private Object _oid = null;
|
||||
|
||||
// the managing persistence manager and lifecycle state
|
||||
private final BrokerImpl _broker;
|
||||
private transient BrokerImpl _broker; // this is serialized specially
|
||||
private PCState _state = PCState.TRANSIENT;
|
||||
|
||||
// the current and last loaded version indicators, and the lock object
|
||||
|
@ -142,7 +146,7 @@ public class StateManagerImpl
|
|||
|
||||
// information about the owner of this instance, if it is embedded
|
||||
private StateManagerImpl _owner = null;
|
||||
private ValueMetaData _ownerMeta = null;
|
||||
private int _ownerIndex = -1;
|
||||
|
||||
/**
|
||||
* Constructor; supply id, type metadata, and owning persistence manager.
|
||||
|
@ -163,7 +167,7 @@ public class StateManagerImpl
|
|||
*/
|
||||
void setOwner(StateManagerImpl owner, ValueMetaData ownerMeta) {
|
||||
_owner = owner;
|
||||
_ownerMeta = ownerMeta;
|
||||
_ownerIndex = ownerMeta.getFieldMetaData().getIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -371,7 +375,7 @@ public class StateManagerImpl
|
|||
// care of checking if the DFG is loaded, making sure version info
|
||||
// is loaded, etc
|
||||
int lockLevel = calculateLockLevel(active, forWrite, fetch);
|
||||
boolean ret = loadFields(fields, fetch, lockLevel, sdata, forWrite);
|
||||
boolean ret = loadFields(fields, fetch, lockLevel, sdata);
|
||||
obtainLocks(active, forWrite, lockLevel, fetch, sdata);
|
||||
return ret;
|
||||
}
|
||||
|
@ -395,8 +399,8 @@ public class StateManagerImpl
|
|||
return _owner;
|
||||
}
|
||||
|
||||
public ValueMetaData getOwnerMetaData() {
|
||||
return _ownerMeta;
|
||||
public int getOwnerIndex() {
|
||||
return _ownerIndex;
|
||||
}
|
||||
|
||||
public boolean isEmbedded() {
|
||||
|
@ -594,9 +598,9 @@ public class StateManagerImpl
|
|||
|
||||
// Throw exception if field already has a value assigned.
|
||||
// @GeneratedValue overrides POJO initial values and setter methods
|
||||
if (!isDefaultValue(field) && !fmd.isValueGenerated())
|
||||
if (!fmd.isValueGenerated() && !isDefaultValue(field))
|
||||
throw new InvalidStateException(_loc.get(
|
||||
"existing-value-override-excep", fmd.getFullName(false)));
|
||||
"existing-value-override-excep", fmd.getFullName(false)));
|
||||
|
||||
// for primary key fields, assign the object id and recache so that
|
||||
// to the user, so it looks like the oid always matches the pk fields
|
||||
|
@ -1318,7 +1322,16 @@ public class StateManagerImpl
|
|||
// Implementation of StateManager interface
|
||||
////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @return whether or not unloaded fields should be closed.
|
||||
*/
|
||||
public boolean serializing() {
|
||||
// if the broker is in the midst of a serialization, then no special
|
||||
// handling should be performed on the instance, and no subsequent
|
||||
// load should happen
|
||||
if (_broker.isSerializing())
|
||||
return false;
|
||||
|
||||
try {
|
||||
if (_meta.isDetachable())
|
||||
return DetachManager.preSerialize(this);
|
||||
|
@ -1510,8 +1523,7 @@ public class StateManagerImpl
|
|||
|
||||
if (isEmbedded()) {
|
||||
// notify owner of change
|
||||
_owner.dirty(_ownerMeta.getFieldMetaData().getIndex(),
|
||||
Boolean.TRUE, loadFetchGroup);
|
||||
_owner.dirty(_ownerIndex, Boolean.TRUE, loadFetchGroup);
|
||||
}
|
||||
|
||||
// is this a direct mutation of an sco field?
|
||||
|
@ -2862,7 +2874,7 @@ public class StateManagerImpl
|
|||
* Return true if any data is loaded, false otherwise.
|
||||
*/
|
||||
boolean loadFields(BitSet fields, FetchConfiguration fetch, int lockLevel,
|
||||
Object sdata, boolean forWrite) {
|
||||
Object sdata) {
|
||||
// can't load version field from store
|
||||
if (fields != null) {
|
||||
FieldMetaData vfield = _meta.getVersionField();
|
||||
|
@ -2956,7 +2968,7 @@ public class StateManagerImpl
|
|||
// call this method even if there are no unloaded fields; loadFields
|
||||
// takes care of things like loading version info and setting PC flags
|
||||
try {
|
||||
loadFields(fields, fetch, lockLevel, null, forWrite);
|
||||
loadFields(fields, fetch, lockLevel, null);
|
||||
} finally {
|
||||
if (lfgAdded)
|
||||
fetch.removeFetchGroup(lfg);
|
||||
|
@ -3154,4 +3166,66 @@ public class StateManagerImpl
|
|||
// manager lock and broker lock being obtained in different orders
|
||||
_broker.unlock ();
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream oos) throws IOException {
|
||||
oos.writeObject(_broker);
|
||||
oos.defaultWriteObject();
|
||||
oos.writeObject(_meta.getDescribedType());
|
||||
writePC(oos, _pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write <code>pc</code> to <code>oos</code>, handling internal-form
|
||||
* serialization. <code>pc</code> must be of the same type that this
|
||||
* state manager manages.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
void writePC(ObjectOutputStream oos, PersistenceCapable pc)
|
||||
throws IOException {
|
||||
if (!Serializable.class.isAssignableFrom(_meta.getDescribedType()))
|
||||
throw new NotSerializableException(
|
||||
_meta.getDescribedType().getName());
|
||||
|
||||
oos.writeObject(pc);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
_broker = (BrokerImpl) in.readObject();
|
||||
in.defaultReadObject();
|
||||
|
||||
// we need to store the class before the pc instance so that we can
|
||||
// create _meta before calling readPC(), which relies on _meta being
|
||||
// non-null when reconstituting ReflectingPC instances. Sadly, this
|
||||
// penalizes the serialization footprint of non-ReflectingPC SMs also.
|
||||
Class managedType = (Class) in.readObject();
|
||||
_meta = _broker.getConfiguration().getMetaDataRepositoryInstance()
|
||||
.getMetaData(managedType, null, true);
|
||||
|
||||
_pc = readPC(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the deserialized <code>o</code> to a {@link PersistenceCapable}
|
||||
* instance appropriate for storing in <code>_pc</code>.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
PersistenceCapable readPC(ObjectInputStream in)
|
||||
throws ClassNotFoundException, IOException {
|
||||
Object o = in.readObject();
|
||||
|
||||
if (o == null)
|
||||
return null;
|
||||
|
||||
PersistenceCapable pc;
|
||||
if (!(o instanceof PersistenceCapable))
|
||||
pc = ImplHelper.toPersistenceCapable(o, this);
|
||||
else
|
||||
pc = (PersistenceCapable) o;
|
||||
|
||||
pc.pcReplaceStateManager(this);
|
||||
return pc;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,10 @@ public class GeneralException
|
|||
super(msg, cause);
|
||||
}
|
||||
|
||||
public GeneralException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return GENERAL;
|
||||
}
|
||||
|
|
|
@ -304,6 +304,11 @@ public class ImplHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static void registerPersistenceCapable(
|
||||
ReflectingPersistenceCapable pc) {
|
||||
_unenhancedInstanceMap.put(pc.getManagedInstance(), pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the user-visible representation of <code>o</code>.
|
||||
* @since 1.0.0
|
||||
|
|
|
@ -390,3 +390,9 @@ multi-threaded-access: Multiple concurrent threads attempted to access a \
|
|||
openjpa.Multithreaded property to true to override the default behavior.
|
||||
no-saved-fields: No state snapshot is available for "{0}", but this instance \
|
||||
uses state-comparison for dirty detection.
|
||||
cant-serialize-flushed-broker: Serialization not allowed once a broker has \
|
||||
been flushed.
|
||||
cant-serialize-pessimistic-broker: Serialization not allowed for brokers with \
|
||||
an active datastore (pessimistic) transaction.
|
||||
cant-serialize-connected-broker: Serialization not allowed for brokers with \
|
||||
an active connection to the database.
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.enhance;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class TestPCSubclassNameConversion
|
||||
extends TestCase {
|
||||
|
||||
public void testPCSubclassNameConversion() {
|
||||
String name = PCEnhancer.toPCSubclassName(Object.class);
|
||||
assertTrue(PCEnhancer.isPCSubclassName(name));
|
||||
assertEquals(Object.class.getName(),
|
||||
PCEnhancer.toManagedTypeName(name));
|
||||
}
|
||||
}
|
|
@ -648,13 +648,15 @@ public class ConfigurationImpl
|
|||
Configurations.removeProperty("properties", remaining);
|
||||
|
||||
// now warn if there are any remaining properties that there
|
||||
// is an unhandled prop
|
||||
// is an unhandled prop, and remove the unknown properties
|
||||
Map.Entry entry;
|
||||
for (Iterator itr = remaining.entrySet().iterator(); itr.hasNext();) {
|
||||
entry = (Map.Entry) itr.next();
|
||||
if (entry.getKey() != null)
|
||||
warnInvalidProperty((String) entry.getKey());
|
||||
ser &= entry.getValue() instanceof Serializable;
|
||||
Object key = entry.getKey();
|
||||
if (key != null) {
|
||||
warnInvalidProperty((String) key);
|
||||
map.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
// cache properties
|
||||
|
|
|
@ -49,7 +49,11 @@ public class ReferenceHashSet implements Set, Serializable {
|
|||
*/
|
||||
public static final int WEAK = 2;
|
||||
|
||||
private static final Object DUMMY_VAL = new Object();
|
||||
private static final Object DUMMY_VAL = new Serializable() {
|
||||
public String toString() {
|
||||
return ReferenceHashSet.class.getName() + ".DUMMY_VAL";
|
||||
}
|
||||
};
|
||||
|
||||
private final Set _set;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.apache.openjpa.lib.util.concurrent;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
@ -35,7 +36,8 @@ import org.apache.openjpa.lib.util.EventManager;
|
|||
*
|
||||
* @author Abe White
|
||||
*/
|
||||
public abstract class AbstractConcurrentEventManager implements EventManager {
|
||||
public abstract class AbstractConcurrentEventManager
|
||||
implements EventManager, Serializable {
|
||||
|
||||
private static Exception[] EMPTY_EXCEPTIONS = new Exception[0];
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ public abstract class AbstractUnenhancedClassTest
|
|||
PersistenceCapable pc = PCRegistry.newInstance(
|
||||
getUnenhancedClass(), null, false);
|
||||
assertNotNull(pc);
|
||||
assertEquals(pc.getClass(), PCRegistry.getPCType(getUnenhancedClass()));
|
||||
}
|
||||
|
||||
public void testClearingOnSubtypeInstance() {
|
||||
|
|
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.apache.openjpa.event.AbstractLifecycleListener;
|
||||
import org.apache.openjpa.event.AbstractTransactionListener;
|
||||
import org.apache.openjpa.event.LifecycleEvent;
|
||||
import org.apache.openjpa.event.TransactionEvent;
|
||||
import org.apache.openjpa.persistence.InvalidStateException;
|
||||
import org.apache.openjpa.persistence.JPAFacadeHelper;
|
||||
import org.apache.openjpa.persistence.OpenJPAEntityManager;
|
||||
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
|
||||
import org.apache.openjpa.persistence.jdbc.JDBCFetchPlan;
|
||||
import org.apache.openjpa.persistence.jdbc.JoinSyntax;
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
/*
|
||||
* To test:
|
||||
* - managed transactions
|
||||
* - converting non-enhanced classes to enhanced subclasses
|
||||
* (maybe an ugly ThreadLocal, maybe through PCData?)
|
||||
*/
|
||||
public abstract class AbstractBrokerSerializationTest<T>
|
||||
extends SingleEMFTestCase {
|
||||
|
||||
private static LifeListener deserializedLifeListener;
|
||||
private static int testGlobalRefreshCount = 0;
|
||||
|
||||
private static TxListener deserializedTxListener;
|
||||
private static int testGlobalBeginCount = 0;
|
||||
|
||||
|
||||
private Object id;
|
||||
|
||||
public void setUp() {
|
||||
testGlobalRefreshCount = 0;
|
||||
deserializedLifeListener = null;
|
||||
testGlobalBeginCount = 0;
|
||||
deserializedTxListener = null;
|
||||
|
||||
setUp(getManagedType(), getSecondaryType(), CLEAR_TABLES,
|
||||
"openjpa.EntityManagerFactoryPool", "true");
|
||||
|
||||
T e = newManagedInstance();
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.persist(e);
|
||||
em.getTransaction().commit();
|
||||
id = em.getObjectId(e);
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
testGlobalRefreshCount = 0;
|
||||
deserializedLifeListener = null;
|
||||
testGlobalBeginCount = 0;
|
||||
deserializedTxListener = null;
|
||||
}
|
||||
|
||||
public void testEmptyBrokerSerialization() {
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
OpenJPAEntityManager em2 = deserializeEM(serialize(em));
|
||||
|
||||
assertTrue(em != em2);
|
||||
assertTrue(
|
||||
JPAFacadeHelper.toBroker(em) != JPAFacadeHelper.toBroker(em2));
|
||||
assertSame(em.getEntityManagerFactory(), em2.getEntityManagerFactory());
|
||||
|
||||
assertSame(em2, JPAFacadeHelper.toBroker(em2)
|
||||
.getUserObject(JPAFacadeHelper.EM_KEY));
|
||||
|
||||
em.close();
|
||||
assertTrue(em2.isOpen());
|
||||
em2.close();
|
||||
}
|
||||
|
||||
public void testNontransactionalBrokerSerialization() {
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
T e = em.find(getManagedType(), id);
|
||||
OpenJPAEntityManager em2 = deserializeEM(serialize(em));
|
||||
|
||||
assertFalse(em2.getTransaction().isActive());
|
||||
|
||||
assertFalse(em2.contains(e));
|
||||
assertEquals(1*graphSize(), em2.getManagedObjects().size());
|
||||
T e2 = em2.find(getManagedType(), id);
|
||||
assertEquals(em.getObjectId(e), em2.getObjectId(e2));
|
||||
|
||||
em.close();
|
||||
em2.close();
|
||||
}
|
||||
|
||||
public void testUnflushedOptimisticTxBrokerSerialization() {
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
T e = em.find(getManagedType(), id);
|
||||
OpenJPAEntityManager em2 = null;
|
||||
OpenJPAEntityManager em3 = null;
|
||||
try {
|
||||
em.getTransaction().begin();
|
||||
modifyInstance(e);
|
||||
T newe = newManagedInstance();
|
||||
em.persist(newe);
|
||||
em2 = deserializeEM(serialize(em));
|
||||
|
||||
assertTrue(em2.getTransaction().isActive());
|
||||
|
||||
assertFalse(em2.contains(e));
|
||||
T e2 = em2.find(getManagedType(), id);
|
||||
assertEquals(em.getObjectId(e), em2.getObjectId(e2));
|
||||
|
||||
assertEquals("modified", getModifiedValue(e2));
|
||||
|
||||
em.getTransaction().rollback();
|
||||
assertTrue(em2.getTransaction().isActive());
|
||||
em2.getTransaction().commit();
|
||||
|
||||
em3 = emf.createEntityManager();
|
||||
T e3 = em3.find(getManagedType(), id);
|
||||
assertEquals(getModifiedValue(e2), getModifiedValue(e3));
|
||||
assertTrue(1 < ((Number) em3.createQuery("select count(o) from "
|
||||
+ getManagedType().getName() + " o").getSingleResult())
|
||||
.intValue());
|
||||
} finally {
|
||||
close(em);
|
||||
close(em2);
|
||||
close(em3);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFlushedOptimisticTxBrokerSerialization() {
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
T e = em.find(getManagedType(), id);
|
||||
em.getTransaction().begin();
|
||||
modifyInstance(e);
|
||||
em.flush();
|
||||
try {
|
||||
serialize(em);
|
||||
} catch (InvalidStateException ise) {
|
||||
// expected
|
||||
assertTrue(ise.getMessage().contains("flushed"));
|
||||
} finally {
|
||||
em.getTransaction().rollback();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testConnectedOptimisticTxBrokerSerialization() {
|
||||
Map m = new HashMap();
|
||||
m.put("openjpa.ConnectionRetainMode", "always");
|
||||
OpenJPAEntityManager em = emf.createEntityManager(m);
|
||||
try {
|
||||
serialize(em);
|
||||
} catch (InvalidStateException ise) {
|
||||
// expected
|
||||
assertTrue(ise.getMessage().contains("connected"));
|
||||
} finally {
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testEmptyPessimisticTxBrokerSerialization() {
|
||||
Map m = new HashMap();
|
||||
m.put("openjpa.Optimistic", "false");
|
||||
OpenJPAEntityManager em = emf.createEntityManager(m);
|
||||
em.getTransaction().begin();
|
||||
try {
|
||||
serialize(em);
|
||||
fail("should not be able to serialize");
|
||||
} catch (InvalidStateException ise) {
|
||||
// expected
|
||||
assertTrue(ise.getMessage().contains("datastore (pessimistic)"));
|
||||
} finally {
|
||||
em.getTransaction().rollback();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testNonEmptyPessimisticTxBrokerSerialization() {
|
||||
Map m = new HashMap();
|
||||
m.put("openjpa.Optimistic", "false");
|
||||
OpenJPAEntityManager em = emf.createEntityManager(m);
|
||||
T e = em.find(getManagedType(), id);
|
||||
em.getTransaction().begin();
|
||||
try {
|
||||
serialize(em);
|
||||
fail("should not be able to serialize");
|
||||
} catch (InvalidStateException ise) {
|
||||
// expected
|
||||
assertTrue(ise.getMessage().contains("datastore (pessimistic)"));
|
||||
} finally {
|
||||
em.getTransaction().rollback();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testFetchConfigurationMutations() {
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
JDBCFetchPlan plan = (JDBCFetchPlan) em.getFetchPlan();
|
||||
|
||||
assertNotEquals(17, plan.getLockTimeout());
|
||||
assertNotEquals(JoinSyntax.TRADITIONAL, plan.getJoinSyntax());
|
||||
|
||||
plan.setLockTimeout(17);
|
||||
plan.setJoinSyntax(JoinSyntax.TRADITIONAL);
|
||||
|
||||
OpenJPAEntityManager em2 = deserializeEM(serialize(em));
|
||||
JDBCFetchPlan plan2 = (JDBCFetchPlan) em2.getFetchPlan();
|
||||
assertEquals(17, plan2.getLockTimeout());
|
||||
assertEquals(JoinSyntax.TRADITIONAL, plan2.getJoinSyntax());
|
||||
}
|
||||
|
||||
public void testInMemorySavepointsWithNewInstances() {
|
||||
emf.close();
|
||||
OpenJPAEntityManagerFactory emf = createEMF(
|
||||
getManagedType(), getSecondaryType(),
|
||||
"openjpa.EntityManagerFactoryPool", "true",
|
||||
"openjpa.SavepointManager", "in-mem");
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
OpenJPAEntityManager em2 = null;
|
||||
try {
|
||||
em.getTransaction().begin();
|
||||
T t = newManagedInstance();
|
||||
Object orig = getModifiedValue(t);
|
||||
em.persist(t);
|
||||
Object id = em.getObjectId(t);
|
||||
em.setSavepoint("foo");
|
||||
modifyInstance(t);
|
||||
assertNotEquals(orig, getModifiedValue(t));
|
||||
|
||||
em2 = deserializeEM(serialize(em));
|
||||
T t2 = em2.find(getManagedType(), id);
|
||||
assertNotEquals(orig, getModifiedValue(t2));
|
||||
|
||||
em.rollbackToSavepoint("foo");
|
||||
assertEquals(orig, getModifiedValue(t));
|
||||
|
||||
em2.rollbackToSavepoint("foo");
|
||||
assertEquals(orig, getModifiedValue(t2));
|
||||
} finally {
|
||||
close(em);
|
||||
close(em2);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInMemorySavepointsWithModifiedInstances() {
|
||||
emf.close();
|
||||
OpenJPAEntityManagerFactory emf = createEMF(
|
||||
getManagedType(), getSecondaryType(),
|
||||
"openjpa.EntityManagerFactoryPool", "true",
|
||||
"openjpa.SavepointManager", "in-mem");
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
OpenJPAEntityManager em2 = null;
|
||||
try {
|
||||
em.getTransaction().begin();
|
||||
T t = em.find(getManagedType(), id);
|
||||
Object orig = getModifiedValue(t);
|
||||
em.setSavepoint("foo");
|
||||
modifyInstance(t);
|
||||
assertNotEquals(orig, getModifiedValue(t));
|
||||
|
||||
em2 = deserializeEM(serialize(em));
|
||||
T t2 = em2.find(getManagedType(), id);
|
||||
assertNotEquals(orig, getModifiedValue(t2));
|
||||
|
||||
em.rollbackToSavepoint("foo");
|
||||
assertEquals(orig, getModifiedValue(t));
|
||||
|
||||
em2.rollbackToSavepoint("foo");
|
||||
assertEquals(orig, getModifiedValue(t2));
|
||||
} finally {
|
||||
close(em);
|
||||
close(em2);
|
||||
}
|
||||
}
|
||||
|
||||
public void testEventManagers() {
|
||||
TxListener txListener = new TxListener();
|
||||
emf.addTransactionListener(txListener);
|
||||
LifeListener lifeListener = new LifeListener();
|
||||
emf.addLifecycleListener(lifeListener, null);
|
||||
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
T t = em.find(getManagedType(), id);
|
||||
assertEquals(0, lifeListener.refreshCount);
|
||||
em.refresh(t);
|
||||
assertEquals(1*graphSize(), lifeListener.refreshCount);
|
||||
em.getTransaction().begin();
|
||||
em.getTransaction().commit();
|
||||
em.getTransaction().begin();
|
||||
em.getTransaction().commit();
|
||||
assertEquals(2, txListener.beginCount);
|
||||
|
||||
OpenJPAEntityManager em2 = deserializeEM(serialize(em));
|
||||
assertNotNull(deserializedLifeListener);
|
||||
assertEquals(1* graphSize(),
|
||||
deserializedLifeListener.refreshCount);
|
||||
assertNotSame(lifeListener, deserializedLifeListener);
|
||||
T t2 = em2.find(getManagedType(), id);
|
||||
em2.refresh(t2);
|
||||
assertEquals(2* graphSize(),
|
||||
deserializedLifeListener.refreshCount);
|
||||
|
||||
// if this is 3*refreshMultiplier(), that means that there are
|
||||
// extra registered listeners
|
||||
assertEquals(2* graphSize(), testGlobalRefreshCount);
|
||||
|
||||
|
||||
assertNotNull(deserializedTxListener);
|
||||
assertEquals(2, deserializedTxListener.beginCount);
|
||||
assertNotSame(txListener, deserializedTxListener);
|
||||
em2.getTransaction().begin();
|
||||
em2.getTransaction().rollback();
|
||||
assertEquals(3, deserializedTxListener.beginCount);
|
||||
|
||||
// if this is 4, that means that there are extra registered listeners
|
||||
assertEquals(3, testGlobalBeginCount);
|
||||
}
|
||||
|
||||
byte[] serialize(Object o) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
oos.flush();
|
||||
return baos.toByteArray();
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
OpenJPAEntityManager deserializeEM(byte[] bytes) {
|
||||
return (OpenJPAEntityManager) deserialize(bytes);
|
||||
}
|
||||
|
||||
private Object deserialize(byte[] bytes) {
|
||||
try {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
return ois.readObject();
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
void close(EntityManager em) {
|
||||
if (em != null && em.isOpen() && em.getTransaction().isActive())
|
||||
em.getTransaction().rollback();
|
||||
if (em != null && em.isOpen())
|
||||
em.close();
|
||||
}
|
||||
|
||||
protected abstract Class<T> getManagedType();
|
||||
|
||||
protected abstract T newManagedInstance();
|
||||
|
||||
protected abstract void modifyInstance(T t);
|
||||
|
||||
protected abstract Object getModifiedValue(T t);
|
||||
|
||||
/**
|
||||
* The number of instances in the graph created
|
||||
* by {@link #newManagedInstance()} of type T.
|
||||
*/
|
||||
protected int graphSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* An additional type that must be available in this PC. May be null.
|
||||
*/
|
||||
protected Class getSecondaryType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class TxListener
|
||||
extends AbstractTransactionListener
|
||||
implements Serializable {
|
||||
|
||||
private int beginCount = 0;
|
||||
|
||||
public TxListener() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterBegin(TransactionEvent event) {
|
||||
beginCount++;
|
||||
testGlobalBeginCount++;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws ClassNotFoundException, IOException {
|
||||
in.defaultReadObject();
|
||||
deserializedTxListener = this;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LifeListener
|
||||
extends AbstractLifecycleListener
|
||||
implements Serializable {
|
||||
|
||||
private int refreshCount = 0;
|
||||
|
||||
@Override
|
||||
public void afterRefresh(LifecycleEvent event) {
|
||||
refreshCount++;
|
||||
testGlobalRefreshCount++;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws ClassNotFoundException, IOException {
|
||||
in.defaultReadObject();
|
||||
deserializedLifeListener = this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.apache.openjpa.enhance.UnenhancedSubtype;
|
||||
import org.apache.openjpa.persistence.OpenJPAEntityManager;
|
||||
import org.apache.openjpa.util.ImplHelper;
|
||||
|
||||
public abstract class AbstractUnenhancedRelationBrokerSerializationTest<T>
|
||||
extends AbstractBrokerSerializationTest<T> {
|
||||
|
||||
public void testNewUnenhancedSMsRegisteredGlobally() {
|
||||
OpenJPAEntityManager em = emf.createEntityManager();
|
||||
OpenJPAEntityManager em2 = null;
|
||||
try {
|
||||
em.getTransaction().begin();
|
||||
UnenhancedSubtype newe = (UnenhancedSubtype) newManagedInstance();
|
||||
em.persist(newe);
|
||||
em2 = deserializeEM(serialize(em));
|
||||
|
||||
for (Object o : em2.getManagedObjects()) {
|
||||
assertFalse(o instanceof PersistenceCapable);
|
||||
assertNotNull(ImplHelper.toPersistenceCapable(o,
|
||||
emf.getConfiguration()));
|
||||
if (o instanceof UnenhancedSubtype)
|
||||
assertNotNull(ImplHelper.toPersistenceCapable(
|
||||
((UnenhancedSubtype) o).getRelated(),
|
||||
emf.getConfiguration()));
|
||||
}
|
||||
} finally {
|
||||
close(em);
|
||||
close(em2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.apache.openjpa.persistence.query.SimpleEntity;
|
||||
|
||||
public class TestEnhancedInstanceBrokerSerialization
|
||||
extends AbstractBrokerSerializationTest<SimpleEntity> {
|
||||
|
||||
@Override
|
||||
public void setUp() {
|
||||
assertTrue(
|
||||
PersistenceCapable.class.isAssignableFrom(SimpleEntity.class));
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
protected Class<SimpleEntity> getManagedType() {
|
||||
return SimpleEntity.class;
|
||||
}
|
||||
|
||||
protected SimpleEntity newManagedInstance() {
|
||||
SimpleEntity e = new SimpleEntity();
|
||||
e.setName("foo");
|
||||
e.setValue("bar");
|
||||
return e;
|
||||
}
|
||||
|
||||
protected void modifyInstance(SimpleEntity e) {
|
||||
e.setValue("modified");
|
||||
}
|
||||
|
||||
protected Object getModifiedValue(SimpleEntity e) {
|
||||
return e.getValue();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
public class TestEntityManagerFactoryPool
|
||||
extends SingleEMFTestCase {
|
||||
|
||||
public void setUp() {
|
||||
setUp("openjpa.EntityManagerFactoryPool", Boolean.TRUE);
|
||||
|
||||
emf.createEntityManager().close();
|
||||
}
|
||||
|
||||
public void testBrokerFactoryPoolHit() {
|
||||
Map m = new HashMap();
|
||||
// also tests string values for the property
|
||||
m.put("openjpa.EntityManagerFactoryPool", "True");
|
||||
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
|
||||
"test", m);
|
||||
assertSame(this.emf, emf);
|
||||
}
|
||||
|
||||
public void testBrokerFactoryPoolMiss() {
|
||||
Map m = new HashMap();
|
||||
m.put("openjpa.EntityManagerFactoryPool", Boolean.TRUE);
|
||||
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
|
||||
"second-persistence-unit", m);
|
||||
assertNotSame(this.emf, emf);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import org.apache.openjpa.persistence.query.ManyOneEntity;
|
||||
|
||||
public class TestInstanceGraphBrokerSerialization
|
||||
extends AbstractBrokerSerializationTest<ManyOneEntity> {
|
||||
|
||||
protected Class<ManyOneEntity> getManagedType() {
|
||||
return ManyOneEntity.class;
|
||||
}
|
||||
|
||||
protected ManyOneEntity newManagedInstance() {
|
||||
ManyOneEntity e = new ManyOneEntity();
|
||||
e.setName("foo");
|
||||
ManyOneEntity rel = new ManyOneEntity();
|
||||
rel.setName("bar");
|
||||
e.setRel(rel);
|
||||
return e;
|
||||
}
|
||||
|
||||
protected void modifyInstance(ManyOneEntity e) {
|
||||
e.getRel().setName("modified");
|
||||
}
|
||||
|
||||
protected Object getModifiedValue(ManyOneEntity e) {
|
||||
return e.getRel().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int graphSize() {
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import org.apache.openjpa.enhance.UnenhancedFieldAccess;
|
||||
|
||||
public class TestUnenhancedFieldAccessInstanceBrokerSerialization
|
||||
extends AbstractBrokerSerializationTest<UnenhancedFieldAccess> {
|
||||
|
||||
protected Class<UnenhancedFieldAccess> getManagedType() {
|
||||
return UnenhancedFieldAccess.class;
|
||||
}
|
||||
|
||||
protected UnenhancedFieldAccess newManagedInstance() {
|
||||
UnenhancedFieldAccess e = new UnenhancedFieldAccess();
|
||||
e.setStringField("foo");
|
||||
return e;
|
||||
}
|
||||
|
||||
protected void modifyInstance(UnenhancedFieldAccess e) {
|
||||
e.setStringField("modified");
|
||||
}
|
||||
|
||||
protected Object getModifiedValue(UnenhancedFieldAccess e) {
|
||||
return e.getStringField();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import org.apache.openjpa.enhance.UnenhancedFieldAccess;
|
||||
import org.apache.openjpa.enhance.UnenhancedFieldAccessSubclass;
|
||||
|
||||
public class TestUnenhancedFieldAccessWithRelationInstanceBrokerSerialization
|
||||
extends AbstractUnenhancedRelationBrokerSerializationTest
|
||||
<UnenhancedFieldAccessSubclass> {
|
||||
|
||||
protected Class getSecondaryType() {
|
||||
return UnenhancedFieldAccess.class;
|
||||
}
|
||||
|
||||
protected Class<UnenhancedFieldAccessSubclass> getManagedType() {
|
||||
return UnenhancedFieldAccessSubclass.class;
|
||||
}
|
||||
|
||||
protected UnenhancedFieldAccessSubclass newManagedInstance() {
|
||||
UnenhancedFieldAccessSubclass e = new UnenhancedFieldAccessSubclass();
|
||||
e.setStringField("foo");
|
||||
UnenhancedFieldAccess related = new UnenhancedFieldAccess();
|
||||
related.setStringField("bar");
|
||||
e.setRelated(related);
|
||||
return e;
|
||||
}
|
||||
|
||||
protected void modifyInstance(UnenhancedFieldAccessSubclass e) {
|
||||
e.getRelated().setStringField("modified");
|
||||
}
|
||||
|
||||
protected Object getModifiedValue(UnenhancedFieldAccessSubclass e) {
|
||||
return e.getRelated().getStringField();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int graphSize() {
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import org.apache.openjpa.enhance.UnenhancedPropertyAccess;
|
||||
|
||||
public class TestUnenhancedPropertyAccessInstanceBrokerSerialization
|
||||
extends AbstractBrokerSerializationTest<UnenhancedPropertyAccess> {
|
||||
|
||||
protected Class<UnenhancedPropertyAccess> getManagedType() {
|
||||
return UnenhancedPropertyAccess.class;
|
||||
}
|
||||
|
||||
protected UnenhancedPropertyAccess newManagedInstance() {
|
||||
UnenhancedPropertyAccess e = new UnenhancedPropertyAccess();
|
||||
e.setStringField("foo");
|
||||
return e;
|
||||
}
|
||||
|
||||
protected void modifyInstance(UnenhancedPropertyAccess e) {
|
||||
e.setStringField("modified");
|
||||
}
|
||||
|
||||
protected Object getModifiedValue(UnenhancedPropertyAccess e) {
|
||||
return e.getStringField();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import org.apache.openjpa.enhance.UnenhancedPropertyAccess;
|
||||
import org.apache.openjpa.enhance.UnenhancedPropertyAccessSubclass;
|
||||
|
||||
public class TestUnenhancedPropertyAccessWithRelationInstanceBrokerSerialization
|
||||
extends AbstractUnenhancedRelationBrokerSerializationTest
|
||||
<UnenhancedPropertyAccessSubclass> {
|
||||
|
||||
protected Class getSecondaryType() {
|
||||
return UnenhancedPropertyAccess.class;
|
||||
}
|
||||
|
||||
protected Class<UnenhancedPropertyAccessSubclass> getManagedType() {
|
||||
return UnenhancedPropertyAccessSubclass.class;
|
||||
}
|
||||
|
||||
protected UnenhancedPropertyAccessSubclass newManagedInstance() {
|
||||
UnenhancedPropertyAccessSubclass e =
|
||||
new UnenhancedPropertyAccessSubclass();
|
||||
e.setStringField("foo");
|
||||
UnenhancedPropertyAccess related = new UnenhancedPropertyAccess();
|
||||
related.setStringField("bar");
|
||||
e.setRelated(related);
|
||||
return e;
|
||||
}
|
||||
|
||||
protected void modifyInstance(UnenhancedPropertyAccessSubclass e) {
|
||||
e.getRelated().setStringField("modified");
|
||||
}
|
||||
|
||||
protected Object getModifiedValue(UnenhancedPropertyAccessSubclass e) {
|
||||
return e.getRelated().getStringField();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int graphSize() {
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
|
@ -29,7 +30,7 @@ import javax.persistence.Version;
|
|||
|
||||
@Entity
|
||||
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
|
||||
public class ManyOneEntity {
|
||||
public class ManyOneEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -43,7 +44,7 @@ import javax.persistence.Table;
|
|||
@FieldResult(name = "value", column = "VALUE") }))
|
||||
@Entity(name = "simple")
|
||||
@Table(name = "SIMPLE_ENTITY")
|
||||
public class SimpleEntity {
|
||||
public class SimpleEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -30,6 +39,9 @@ import javax.persistence.Query;
|
|||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.openjpa.conf.OpenJPAConfiguration;
|
||||
import org.apache.openjpa.ee.ManagedRuntime;
|
||||
import org.apache.openjpa.enhance.PCEnhancer;
|
||||
import org.apache.openjpa.enhance.PCRegistry;
|
||||
import org.apache.openjpa.kernel.AbstractBrokerFactory;
|
||||
import org.apache.openjpa.kernel.Broker;
|
||||
import org.apache.openjpa.kernel.DelegatingBroker;
|
||||
import org.apache.openjpa.kernel.FindCallbacks;
|
||||
|
@ -40,8 +52,8 @@ import org.apache.openjpa.kernel.QueryFlushModes;
|
|||
import org.apache.openjpa.kernel.QueryLanguages;
|
||||
import org.apache.openjpa.kernel.Seq;
|
||||
import org.apache.openjpa.kernel.jpql.JPQLParser;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.lib.util.Closeable;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.meta.QueryMetaData;
|
||||
|
@ -59,30 +71,36 @@ import org.apache.openjpa.util.UserException;
|
|||
* @nojavadoc
|
||||
*/
|
||||
public class EntityManagerImpl
|
||||
implements OpenJPAEntityManagerSPI,
|
||||
implements OpenJPAEntityManagerSPI, Externalizable,
|
||||
FindCallbacks, OpCallbacks, Closeable, OpenJPAEntityTransaction {
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
(EntityManagerImpl.class);
|
||||
|
||||
private final DelegatingBroker _broker;
|
||||
private final EntityManagerFactoryImpl _emf;
|
||||
private FetchPlan _fetch = null;
|
||||
private static final Object[] EMPTY_OBJECTS = new Object[0];
|
||||
|
||||
private DelegatingBroker _broker;
|
||||
private EntityManagerFactoryImpl _emf;
|
||||
private FetchPlan _fetch = null;
|
||||
|
||||
private RuntimeExceptionTranslator ret =
|
||||
PersistenceExceptions.getRollbackTranslator(this);
|
||||
|
||||
public EntityManagerImpl() {
|
||||
// for Externalizable
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor; supply factory and delegate.
|
||||
*/
|
||||
public EntityManagerImpl(EntityManagerFactoryImpl factory,
|
||||
Broker broker) {
|
||||
initialize(factory, broker);
|
||||
}
|
||||
|
||||
private void initialize(EntityManagerFactoryImpl factory, Broker broker) {
|
||||
_emf = factory;
|
||||
RuntimeExceptionTranslator translator =
|
||||
PersistenceExceptions.getRollbackTranslator(this);
|
||||
_broker = new DelegatingBroker(broker, translator);
|
||||
_broker.setImplicitBehavior(this, translator);
|
||||
_broker = new DelegatingBroker(broker, ret);
|
||||
_broker.setImplicitBehavior(this, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1180,4 +1198,144 @@ public class EntityManagerImpl
|
|||
return false;
|
||||
return _broker.equals(((EntityManagerImpl) other)._broker);
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
ret = PersistenceExceptions.getRollbackTranslator(this);
|
||||
|
||||
// this assumes that serialized Brokers are from something
|
||||
// that extends AbstractBrokerFactory.
|
||||
Object factoryKey = in.readObject();
|
||||
AbstractBrokerFactory factory =
|
||||
AbstractBrokerFactory.getPooledFactoryForKey(factoryKey);
|
||||
byte[] brokerBytes = (byte[]) in.readObject();
|
||||
ObjectInputStream innerIn = new BrokerBytesInputStream(brokerBytes,
|
||||
factory.getConfiguration());
|
||||
|
||||
Broker broker = (Broker) innerIn.readObject();
|
||||
EntityManagerFactoryImpl emf = (EntityManagerFactoryImpl)
|
||||
JPAFacadeHelper.toEntityManagerFactory(
|
||||
broker.getBrokerFactory());
|
||||
broker.putUserObject(JPAFacadeHelper.EM_KEY, this);
|
||||
initialize(emf, broker);
|
||||
} catch (RuntimeException re) {
|
||||
try {
|
||||
re = ret.translate(re);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
try {
|
||||
// this requires that only AbstractBrokerFactory-sourced
|
||||
// brokers can be serialized
|
||||
Object factoryKey = ((AbstractBrokerFactory) _broker
|
||||
.getBrokerFactory()).getPoolKey();
|
||||
out.writeObject(factoryKey);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream innerOut = new ObjectOutputStream(baos);
|
||||
innerOut.writeObject(_broker.getDelegate());
|
||||
innerOut.flush();
|
||||
out.writeObject(baos.toByteArray());
|
||||
} catch (RuntimeException re) {
|
||||
try {
|
||||
re = ret.translate(re);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
private static class BrokerBytesInputStream extends ObjectInputStream {
|
||||
|
||||
private OpenJPAConfiguration conf;
|
||||
|
||||
BrokerBytesInputStream(byte[] bytes, OpenJPAConfiguration conf)
|
||||
throws IOException {
|
||||
super(new ByteArrayInputStream(bytes));
|
||||
if (conf == null)
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal null argument to ObjectInputStreamWithLoader");
|
||||
this.conf = conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a primitive array class
|
||||
*/
|
||||
private Class primitiveType(char type) {
|
||||
switch (type) {
|
||||
case 'B': return byte.class;
|
||||
case 'C': return char.class;
|
||||
case 'D': return double.class;
|
||||
case 'F': return float.class;
|
||||
case 'I': return int.class;
|
||||
case 'J': return long.class;
|
||||
case 'S': return short.class;
|
||||
case 'Z': return boolean.class;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected Class resolveClass(ObjectStreamClass classDesc)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
String cname = classDesc.getName();
|
||||
if (cname.startsWith("[")) {
|
||||
// An array
|
||||
Class component; // component class
|
||||
int dcount; // dimension
|
||||
for (dcount=1; cname.charAt(dcount)=='['; dcount++) ;
|
||||
if (cname.charAt(dcount) == 'L') {
|
||||
component = lookupClass(cname.substring(dcount+1,
|
||||
cname.length()-1));
|
||||
} else {
|
||||
if (cname.length() != dcount+1) {
|
||||
throw new ClassNotFoundException(cname);// malformed
|
||||
}
|
||||
component = primitiveType(cname.charAt(dcount));
|
||||
}
|
||||
int dim[] = new int[dcount];
|
||||
for (int i=0; i<dcount; i++) {
|
||||
dim[i]=0;
|
||||
}
|
||||
return Array.newInstance(component, dim).getClass();
|
||||
} else {
|
||||
return lookupClass(cname);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a generated subclass, look up the corresponding Class
|
||||
* object via metadata.
|
||||
*/
|
||||
private Class lookupClass(String className)
|
||||
throws ClassNotFoundException {
|
||||
try {
|
||||
return Class.forName(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
if (PCEnhancer.isPCSubclassName(className)) {
|
||||
String superName = PCEnhancer.toManagedTypeName(className);
|
||||
ClassMetaData[] metas = conf.getMetaDataRepositoryInstance()
|
||||
.getMetaDatas();
|
||||
for (int i = 0; i < metas.length; i++) {
|
||||
if (superName.equals(
|
||||
metas[i].getDescribedType().getName())) {
|
||||
return PCRegistry.getPCType(
|
||||
metas[i].getDescribedType());
|
||||
}
|
||||
}
|
||||
|
||||
// if it's not found, try to look for it anyways
|
||||
return Class.forName(className);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,8 +51,8 @@ public class PersistenceExceptions
|
|||
* and {@link NonUniqueResultException} in accordance with
|
||||
* section 3.7 of the EJB 3.0 specification.
|
||||
*/
|
||||
public static RuntimeExceptionTranslator getRollbackTranslator
|
||||
(final OpenJPAEntityManager em) {
|
||||
public static RuntimeExceptionTranslator getRollbackTranslator(
|
||||
final OpenJPAEntityManager em) {
|
||||
return new RuntimeExceptionTranslator() {
|
||||
private boolean throwing = false;
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ import java.lang.instrument.ClassFileTransformer;
|
|||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.spi.ClassTransformer;
|
||||
import javax.persistence.spi.PersistenceProvider;
|
||||
|
@ -54,6 +56,7 @@ public class PersistenceProviderImpl
|
|||
implements PersistenceProvider {
|
||||
|
||||
static final String CLASS_TRANSFORMER_OPTIONS = "ClassTransformerOptions";
|
||||
private static final String EMF_POOL = "EntityManagerFactoryPool";
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage(
|
||||
PersistenceProviderImpl.class);
|
||||
|
@ -72,17 +75,37 @@ public class PersistenceProviderImpl
|
|||
String resource, Map m) {
|
||||
PersistenceProductDerivation pd = new PersistenceProductDerivation();
|
||||
try {
|
||||
Object poolValue = Configurations.removeProperty(EMF_POOL, m);
|
||||
ConfigurationProvider cp = pd.load(resource, name, m);
|
||||
if (cp == null)
|
||||
return null;
|
||||
|
||||
BrokerFactory factory = Bootstrap.newBrokerFactory(cp, null);
|
||||
BrokerFactory factory = getBrokerFactory(cp, poolValue, null);
|
||||
return JPAFacadeHelper.toEntityManagerFactory(factory);
|
||||
} catch (Exception e) {
|
||||
throw PersistenceExceptions.toPersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private BrokerFactory getBrokerFactory(ConfigurationProvider cp,
|
||||
Object poolValue, ClassLoader loader) {
|
||||
// handle "true" and "false"
|
||||
if (poolValue instanceof String
|
||||
&& ("true".equalsIgnoreCase((String) poolValue)
|
||||
|| "false".equalsIgnoreCase((String) poolValue)))
|
||||
poolValue = Boolean.valueOf((String) poolValue);
|
||||
|
||||
if (poolValue != null && !(poolValue instanceof Boolean)) {
|
||||
// we only support boolean settings for this option currently.
|
||||
throw new IllegalArgumentException(poolValue.toString());
|
||||
}
|
||||
|
||||
if (poolValue == null || !((Boolean) poolValue).booleanValue())
|
||||
return Bootstrap.newBrokerFactory(cp, loader);
|
||||
else
|
||||
return Bootstrap.getBrokerFactory(cp, loader);
|
||||
}
|
||||
|
||||
public OpenJPAEntityManagerFactory createEntityManagerFactory(String name,
|
||||
Map m) {
|
||||
return createEntityManagerFactory(name, null, m);
|
||||
|
@ -92,6 +115,7 @@ public class PersistenceProviderImpl
|
|||
PersistenceUnitInfo pui, Map m) {
|
||||
PersistenceProductDerivation pd = new PersistenceProductDerivation();
|
||||
try {
|
||||
Object poolValue = Configurations.removeProperty(EMF_POOL, m);
|
||||
ConfigurationProvider cp = pd.load(pui, m);
|
||||
if (cp == null)
|
||||
return null;
|
||||
|
@ -117,7 +141,7 @@ public class PersistenceProviderImpl
|
|||
BrokerValue.NON_FINALIZING_ALIAS);
|
||||
}
|
||||
|
||||
BrokerFactory factory = Bootstrap.newBrokerFactory(cp,
|
||||
BrokerFactory factory = getBrokerFactory(cp, poolValue,
|
||||
pui.getClassLoader());
|
||||
if (transformerException != null) {
|
||||
Log log = factory.getConfiguration().getLog(
|
||||
|
|
Loading…
Reference in New Issue