You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2007/11/21 18:41:03 UTC
svn commit: r597155 [1/2] - in /openjpa/trunk:
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/
openjpa-kernel/src/main/java/org/apache/openjpa/enhance/
openjpa-kernel/src/main/j...
Author: pcl
Date: Wed Nov 21 09:40:54 2007
New Revision: 597155
URL: http://svn.apache.org/viewvc?rev=597155&view=rev
Log:
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.
Added:
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ManagedCache.java
openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/
openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestPCSubclassNameConversion.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/AbstractBrokerSerializationTest.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/AbstractUnenhancedRelationBrokerSerializationTest.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestEnhancedInstanceBrokerSerialization.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestEntityManagerFactoryPool.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestInstanceGraphBrokerSerialization.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestUnenhancedFieldAccessInstanceBrokerSerialization.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestUnenhancedFieldAccessWithRelationInstanceBrokerSerialization.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestUnenhancedPropertyAccessInstanceBrokerSerialization.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/kernel/TestUnenhancedPropertyAccessWithRelationInstanceBrokerSerialization.java
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSavepointManager.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ReflectingPersistenceCapable.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/event/LifecycleEventManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateAttachStrategy.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPASavepoint.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SavepointFieldManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneralException.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java
openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java
openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/AbstractConcurrentEventManager.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/ManyOneEntity.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/SimpleEntity.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceExceptions.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSavepointManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSavepointManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSavepointManager.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSavepointManager.java Wed Nov 21 09:40:54 2007
@@ -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;
@@ -133,6 +136,11 @@
public void save(Collection states) {
AbstractJDBCSavepointManager.this.setDataStore(this);
super.save(states);
+ }
+
+ private void writeObject(ObjectOutputStream out)
+ throws IOException {
+ throw new NotSerializableException();
}
}
}
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java Wed Nov 21 09:40:54 2007
@@ -582,8 +582,8 @@
return _owner;
}
- public ValueMetaData getOwnerMetaData() {
- return _vmd;
+ public int getOwnerIndex() {
+ return _vmd.getFieldMetaData().getIndex();
}
public boolean isEmbedded() {
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java Wed Nov 21 09:40:54 2007
@@ -246,6 +246,36 @@
}
/**
+ * 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.
*/
public PCEnhancer(OpenJPAConfiguration conf, BCClass type,
@@ -2718,6 +2748,9 @@
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();
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java Wed Nov 21 09:40:54 2007
@@ -122,6 +122,17 @@
}
/**
+ * 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.
*/
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ReflectingPersistenceCapable.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ReflectingPersistenceCapable.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ReflectingPersistenceCapable.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ReflectingPersistenceCapable.java Wed Nov 21 09:40:54 2007
@@ -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.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.JavaTypes;
import org.apache.openjpa.meta.FieldMetaData;
-import org.apache.openjpa.conf.OpenJPAConfiguration;
+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 @@
* @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 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 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 @@
// ##### 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);
@@ -349,5 +370,18 @@
Field field = (Field) meta.getField(i).getBackingMember();
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);
}
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/event/LifecycleEventManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/event/LifecycleEventManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/event/LifecycleEventManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/event/LifecycleEventManager.java Wed Nov 21 09:40:54 2007
@@ -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 @@
* @nojavadoc
*/
public class LifecycleEventManager
- implements CallbackModes {
+ implements CallbackModes, Serializable {
private static final Exception[] EMPTY_EXCEPTIONS = new Exception[0];
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java Wed Nov 21 09:40:54 2007
@@ -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.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 @@
/**
* 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 @@
* 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 @@
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 @@
}
}
+ 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 @@
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
@@ -754,6 +777,15 @@
*/
public Collection getOpenBrokers() {
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());
}
/**
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java Wed Nov 21 09:40:54 2007
@@ -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 @@
* @author Abe White
*/
public class BrokerImpl
- implements Broker, FindCallbacks, Cloneable {
+ implements Broker, FindCallbacks, Cloneable, Serializable {
/**
* Incremental flush.
@@ -132,30 +135,35 @@
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 @@
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 @@
// (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 @@
// 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 @@
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 @@
* 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
}
}
+ 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 @@
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 @@
// 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 @@
return (sm == null) ? null : sm.getManagedInstance();
}
- /**
- * Cache of managed objects.
- */
- 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());
+ 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"));
}
- }
- /**
- * 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);
+ try {
+ _isSerializing = true;
+ out.writeObject(_factory.getPoolKey());
+ out.defaultWriteObject();
+ } finally {
+ _isSerializing = false;
}
+ } finally {
+ unlock();
}
+ }
- /**
- * 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;
- }
+ 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);
- // 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;
- }
+ // re-initialize the lock if needed.
+ setMultithreaded(_multithreaded);
- private void dirtyCheck() {
- if (_untracked == null)
- return;
+ if (isActive() && _runtime instanceof LocalManagedRuntime)
+ ((LocalManagedRuntime) _runtime).begin();
+ }
- for (Iterator iter = _untracked.iterator(); iter.hasNext(); )
- ((StateManagerImpl) iter.next()).dirtyCheck();
- }
+ /**
+ * Whether or not this broker is in the midst of being serialized.
+ *
+ * @since 1.1.0
+ */
+ 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;
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateAttachStrategy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateAttachStrategy.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateAttachStrategy.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateAttachStrategy.java Wed Nov 21 09:40:54 2007
@@ -171,8 +171,7 @@
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];
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java Wed Nov 21 09:40:54 2007
@@ -145,7 +145,7 @@
}
}
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 @@
throw new UnsupportedOperationException();
}
- public ValueMetaData getOwnerMetaData() {
+ public int getOwnerIndex() {
throw new UnsupportedOperationException();
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java Wed Nov 21 09:40:54 2007
@@ -88,8 +88,8 @@
return null;
}
- public ValueMetaData getOwnerMetaData() {
- return null;
+ public int getOwnerIndex() {
+ throw new UnsupportedOperationException();
}
public boolean isEmbedded() {
Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ManagedCache.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ManagedCache.java?rev=597155&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ManagedCache.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ManagedCache.java Wed Nov 21 09:40:54 2007
@@ -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();
+ }
+}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java Wed Nov 21 09:40:54 2007
@@ -309,8 +309,8 @@
return _owner;
}
- public ValueMetaData getOwnerMetaData() {
- return _vmd;
+ public int getOwnerIndex() {
+ return _vmd.getFieldMetaData().getIndex();
}
public boolean isEmbedded() {
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPASavepoint.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPASavepoint.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPASavepoint.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPASavepoint.java Wed Nov 21 09:40:54 2007
@@ -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 @@
* @author Steve Kim
* @since 0.3.4
*/
-public class OpenJPASavepoint {
+public class OpenJPASavepoint implements Serializable {
private final Broker _broker;
private final String _name;
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java Wed Nov 21 09:40:54 2007
@@ -102,9 +102,11 @@
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
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SaveFieldManager.java Wed Nov 21 09:40:54 2007
@@ -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 @@
* @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 @@
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 @@
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 @@
// 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 @@
_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);
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SavepointFieldManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SavepointFieldManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SavepointFieldManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SavepointFieldManager.java Wed Nov 21 09:40:54 2007
@@ -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 @@
* @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 @@
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 @@
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);
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java Wed Nov 21 09:40:54 2007
@@ -20,6 +20,7 @@
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 @@
* @author Abe White
*/
class SingleFieldManager
- extends TransferFieldManager {
+ extends TransferFieldManager
+ implements Serializable {
private static final Localizer _loc = Localizer.forPackage
(SingleFieldManager.class);
@@ -235,7 +237,7 @@
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 @@
// 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);
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java Wed Nov 21 09:40:54 2007
@@ -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 @@
* @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 @@
(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 @@
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 @@
// 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 @@
*/
void setOwner(StateManagerImpl owner, ValueMetaData ownerMeta) {
_owner = owner;
- _ownerMeta = ownerMeta;
+ _ownerIndex = ownerMeta.getFieldMetaData().getIndex();
}
/**
@@ -371,7 +375,7 @@
// 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 @@
return _owner;
}
- public ValueMetaData getOwnerMetaData() {
- return _ownerMeta;
+ public int getOwnerIndex() {
+ return _ownerIndex;
}
public boolean isEmbedded() {
@@ -594,9 +598,9 @@
// 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 @@
// 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 @@
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 @@
* 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 @@
// 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 @@
// 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;
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneralException.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneralException.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneralException.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneralException.java Wed Nov 21 09:40:54 2007
@@ -47,6 +47,10 @@
super(msg, cause);
}
+ public GeneralException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
public int getType() {
return GENERAL;
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java Wed Nov 21 09:40:54 2007
@@ -304,6 +304,11 @@
}
}
+ public static void registerPersistenceCapable(
+ ReflectingPersistenceCapable pc) {
+ _unenhancedInstanceMap.put(pc.getManagedInstance(), pc);
+ }
+
/**
* @return the user-visible representation of <code>o</code>.
* @since 1.0.0
Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties Wed Nov 21 09:40:54 2007
@@ -390,3 +390,9 @@
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.
\ No newline at end of file
Added: openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestPCSubclassNameConversion.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestPCSubclassNameConversion.java?rev=597155&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestPCSubclassNameConversion.java (added)
+++ openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestPCSubclassNameConversion.java Wed Nov 21 09:40:54 2007
@@ -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));
+ }
+}
\ No newline at end of file
Modified: openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java (original)
+++ openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java Wed Nov 21 09:40:54 2007
@@ -648,13 +648,15 @@
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
Modified: openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java (original)
+++ openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/ReferenceHashSet.java Wed Nov 21 09:40:54 2007
@@ -49,7 +49,11 @@
*/
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;
Modified: openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/AbstractConcurrentEventManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/AbstractConcurrentEventManager.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/AbstractConcurrentEventManager.java (original)
+++ openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/AbstractConcurrentEventManager.java Wed Nov 21 09:40:54 2007
@@ -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 @@
*
* @author Abe White
*/
-public abstract class AbstractConcurrentEventManager implements EventManager {
+public abstract class AbstractConcurrentEventManager
+ implements EventManager, Serializable {
private static Exception[] EMPTY_EXCEPTIONS = new Exception[0];
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java?rev=597155&r1=597154&r2=597155&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java Wed Nov 21 09:40:54 2007
@@ -102,6 +102,7 @@
PersistenceCapable pc = PCRegistry.newInstance(
getUnenhancedClass(), null, false);
assertNotNull(pc);
+ assertEquals(pc.getClass(), PCRegistry.getPCType(getUnenhancedClass()));
}
public void testClearingOnSubtypeInstance() {