openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p..@apache.org
Subject svn commit: r560016 [3/4] - in /openjpa/trunk: openjpa-all/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ openjpa...
Date Thu, 26 Jul 2007 22:08:41 GMT
Added: 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?view=auto&rev=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ReflectingPersistenceCapable.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ReflectingPersistenceCapable.java Thu Jul 26 15:08:37 2007
@@ -0,0 +1,353 @@
+/*
+ * 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 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.util.ApplicationIds;
+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
+ * the persistence-capable contract for instances that were not enhanced
+ * before class load time.
+ *
+ * @since 1.0.0
+ */
+public class ReflectingPersistenceCapable
+    implements PersistenceCapable, ManagedInstanceProvider {
+
+    private Object o;
+    private StateManager sm;
+    private PersistenceCapable pcSubclassInstance;
+    private ClassMetaData meta;
+
+    public ReflectingPersistenceCapable(Object o, OpenJPAConfiguration conf) {
+        this.o = o;
+        Class type = o.getClass();
+        pcSubclassInstance = PCRegistry.newInstance(type, null, false);
+        meta = conf.getMetaDataRepositoryInstance()
+            .getMetaData(type, null, true);
+    }
+
+    public int pcGetEnhancementContractVersion() {
+        return PCEnhancer.ENHANCER_VERSION;
+    }
+
+    public Object pcGetGenericContext() {
+        if (sm == null)
+            return null;
+        else
+            return sm.getGenericContext();
+    }
+
+    public StateManager pcGetStateManager() {
+        return sm;
+    }
+
+    public void pcReplaceStateManager(StateManager sm) {
+        this.sm = sm;
+    }
+
+    public void pcProvideField(int i) {
+        switch (meta.getField(i).getTypeCode()) {
+            case JavaTypes.BOOLEAN:
+                sm.providedBooleanField(this, i,
+                    ((Boolean) getValue(i, o)).booleanValue());
+                break;
+            case JavaTypes.BYTE:
+                sm.providedByteField(this, i,
+                    ((Byte) getValue(i, o)).byteValue());
+                break;
+            case JavaTypes.CHAR:
+                sm.providedCharField(this, i,
+                    ((Character) getValue(i, o)).charValue());
+                break;
+            case JavaTypes.DOUBLE:
+                sm.providedDoubleField(this, i,
+                    ((Double) getValue(i, o)).doubleValue());
+                break;
+            case JavaTypes.FLOAT:
+                sm.providedFloatField(this, i,
+                    ((Float) getValue(i, o)).floatValue());
+                break;
+            case JavaTypes.INT:
+                sm.providedIntField(this, i,
+                    ((Integer) getValue(i, o)).intValue());
+                break;
+            case JavaTypes.LONG:
+                sm.providedLongField(this, i,
+                    ((Long) getValue(i, o)).longValue());
+                break;
+            case JavaTypes.SHORT:
+                sm.providedShortField(this, i,
+                    ((Short) getValue(i, o)).shortValue());
+                break;
+            case JavaTypes.STRING:
+                sm.providedStringField(this, i,
+                    (String) getValue(i, o));
+                break;
+            default:
+                sm.providedObjectField(this, i, getValue(i, o));
+                break;
+        }
+    }
+
+    public void pcProvideFields(int[] fieldIndices) {
+        for(int i = 0; i < fieldIndices.length; i++)
+            pcProvideField(fieldIndices[i]);
+    }
+
+    public void pcReplaceField(int i) {
+        switch(meta.getField(i).getTypeCode()) {
+            case JavaTypes.BOOLEAN:
+                setValue(i, o, Boolean.valueOf(
+                    sm.replaceBooleanField(this, i)));
+                break;
+            case JavaTypes.BYTE:
+                setValue(i, o, Byte.valueOf(sm.replaceByteField(this, i)));
+                break;
+            case JavaTypes.CHAR:
+                setValue(i, o, Character.valueOf(sm.replaceCharField(this, i)));
+                break;
+            case JavaTypes.DOUBLE:
+                setValue(i, o, Double.valueOf(sm.replaceDoubleField(this, i)));
+                break;
+            case JavaTypes.FLOAT:
+                setValue(i, o, Float.valueOf(sm.replaceFloatField(this, i)));
+                break;
+            case JavaTypes.INT:
+                setValue(i, o, Integer.valueOf(sm.replaceIntField(this, i)));
+                break;
+            case JavaTypes.LONG:
+                setValue(i, o, Long.valueOf(sm.replaceLongField(this, i)));
+                break;
+            case JavaTypes.SHORT:
+                setValue(i, o, Short.valueOf(sm.replaceShortField(this, i)));
+                break;
+            case JavaTypes.STRING:
+                setValue(i, o, sm.replaceStringField(this, i));
+                break;
+            default:
+                setValue(i, o, sm.replaceObjectField(this, i));
+                break;
+        }
+    }
+
+    public void pcReplaceFields(int[] fieldIndices) {
+        for(int i = 0; i < fieldIndices.length; i++)
+            pcReplaceField(fieldIndices[i]);
+    }
+
+    public void pcCopyField(Object fromObject, int i) {
+        // this doesn't need switch treatment because we're just
+        // reflecting on both sides, bypassing field managers.
+        setValue(i, o, getValue(i, fromObject));
+    }
+
+    public void pcCopyFields(Object fromObject, int[] fieldIndices) {
+        for(int i = 0; i < fieldIndices.length; i++)
+            pcCopyField(fromObject, fieldIndices[i]);
+    }
+
+    public void pcDirty(String fieldName) {
+        if (sm != null)
+            sm.dirty(fieldName);
+    }
+
+    public Object pcFetchObjectId() {
+        if (sm != null)
+            return sm.fetchObjectId();
+        else
+            return null;
+    }
+
+    public Object pcGetVersion() {
+        if (sm == null)
+            return null;
+        else
+            return sm.getVersion();
+    }
+
+    public boolean pcIsDirty() {
+        if (sm == null)
+            return false;
+        else {
+            if (sm instanceof StateManagerImpl)
+                ((StateManagerImpl) sm).dirtyCheck();
+            return sm.isDirty();
+        }
+    }
+
+    public boolean pcIsTransactional() {
+        if (sm == null)
+            return false;
+        else
+            return sm.isTransactional();
+    }
+
+    public boolean pcIsPersistent() {
+        if (sm == null)
+            return false;
+        else
+            return sm.isPersistent();
+    }
+
+    public boolean pcIsNew() {
+        if (sm == null)
+            return false;
+        else
+            return sm.isNew();
+    }
+
+    public boolean pcIsDeleted() {
+        if (sm == null)
+            return false;
+        else
+            return sm.isDeleted();
+    }
+
+    // null == unknown
+    public Boolean pcIsDetached() {
+        if (sm != null)
+            return Boolean.valueOf(sm.isDetached());
+
+        // ##### we could do a lot more here if a detached state field
+        // ##### was specified.
+        return null;
+    }
+
+    public PersistenceCapable pcNewInstance(StateManager sm, boolean clear) {
+        return pcSubclassInstance.pcNewInstance(sm, clear);
+    }
+
+    public PersistenceCapable pcNewInstance(StateManager sm, Object oid,
+        boolean clear) {
+        return pcSubclassInstance.pcNewInstance(sm, oid, clear);
+    }
+
+    public Object pcNewObjectIdInstance() {
+        FieldMetaData[] pkFields = meta.getPrimaryKeyFields();
+        Object[] pks = new Object[pkFields.length];
+        for (int i = 0; i < pkFields.length; i++)
+            pks[i] = getValue(pkFields[i].getIndex(), o);
+        return ApplicationIds.fromPKValues(pks, meta);
+    }
+    
+    public Object pcNewObjectIdInstance(Object oid) {
+        return pcSubclassInstance.pcNewObjectIdInstance(oid);
+    }
+
+    public void pcCopyKeyFieldsToObjectId(Object oid) {
+        Object target;
+        if (oid instanceof ObjectId)
+            target = ((ObjectId) oid).getId();
+        else
+            target = oid;
+
+        FieldMetaData[] pks = meta.getPrimaryKeyFields();
+        for (int i = 0; i < pks.length; i++) {
+            Object val = getValue(pks[i].getIndex(), o);
+            Field f = Reflection.findField(target.getClass(), pks[i].getName(),
+                true);
+            Reflection.set(target, f, val);
+        }
+    }
+
+    public void pcCopyKeyFieldsToObjectId(FieldSupplier supplier, Object obj) {
+        // This is only ever invoked against PCs in the PCRegistry. Such PCs
+        // will always be enhanced types or subtypes of user types, and will
+        // never be a ReflectingPersistenceCapable.
+        throw new InternalException();
+    }
+
+    public void pcCopyKeyFieldsFromObjectId(FieldConsumer consumer,
+        Object obj) {
+        // This is only ever invoked against PCs in the PCRegistry. Such PCs
+        // will always be enhanced types or subtypes of user types, and will
+        // never be a ReflectingPersistenceCapable.
+        throw new InternalException();
+    }
+
+    public Object pcGetDetachedState() {
+        // ##### we can implement this if a state field has been set
+        return null;
+    }
+
+    public void pcSetDetachedState(Object state) {
+        // StateManagerImpl will invoke this with null during instance
+        // initialization
+        if (state != null)
+            throw new UnsupportedOperationException();
+        // ##### we can implement this if a state field has been set
+    }
+
+    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);
+            }
+        } else {
+            Field field = (Field) meta.getField(i).getBackingMember();
+            return Reflection.get(o, field);
+        }
+    }
+
+    private String toFieldName(int i) {
+        if (pcSubclassInstance instanceof AttributeTranslator)
+            return ((AttributeTranslator) pcSubclassInstance)
+                .pcAttributeIndexToFieldName(i);
+        else
+            return meta.getField(i).getName();
+    }
+
+    private void setValue(int i, Object o, Object val) {
+        if (meta.getAccessType() == ClassMetaData.ACCESS_PROPERTY) {
+            if (!meta.isIntercepting()) {
+                Method meth = Reflection.findSetter(meta.getDescribedType(),
+                    meta.getField(i).getName(), true);
+                Reflection.set(o, meth, val);
+            } else {
+                Field field = Reflection.findField(meta.getDescribedType(),
+                    toFieldName(i), true);
+                Reflection.set(o, field, val);
+            }
+        } else {
+            Field field = (Field) meta.getField(i).getBackingMember();
+            Reflection.set(o, field, val);
+        }
+    }
+}

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/Reflection.java Thu Jul 26 15:08:37 2007
@@ -527,6 +527,105 @@
     }
 
     /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, Object value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, boolean value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, byte value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, char value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, double value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, float value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, int value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, long value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
+     * Set the value of the given field in the given object.
+     * Same behavior as above methods, but parameter ordering is rearranged
+     * to simplify usage from generated bytecodes.
+     *
+     * @since 1.0.0
+     */
+    public static void set(Object target, short value, Field field) {
+        set(target, field, value);
+    }
+
+    /**
      * Invoke the given setter on the given object.
      */
     public static void set(Object target, Method setter, Object value) {

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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -28,6 +28,7 @@
 import java.util.Properties;
 import java.util.LinkedList;
 import java.util.List;
+import java.lang.reflect.InvocationTargetException;
 import javax.transaction.Status;
 import javax.transaction.Synchronization;
 import javax.transaction.Transaction;
@@ -38,12 +39,14 @@
 import org.apache.openjpa.conf.OpenJPAVersion;
 import org.apache.openjpa.datacache.DataCacheStoreManager;
 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.lib.log.Log;
 import org.apache.openjpa.lib.util.J2DoPrivHelper;
 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;
@@ -52,6 +55,7 @@
 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}
@@ -216,7 +220,6 @@
         }
 
         if (_transactionListeners != null && !_transactionListeners.isEmpty()) {
-            Map.Entry entry;
             for (Iterator itr = _transactionListeners.iterator();
                 itr.hasNext(); ) {
                 broker.addTransactionListener(itr.next());
@@ -236,6 +239,7 @@
         // cache persistent type names if not already
         ClassLoader loader = _conf.getClassResolverInstance().
             getClassLoader(getClass(), envLoader);
+        Collection toRedefine = new ArrayList();
         if (_pcClassNames == null) {
             Collection clss = _conf.getMetaDataRepositoryInstance().
                 loadPersistentTypes(false, loader);
@@ -243,27 +247,71 @@
                 _pcClassNames = Collections.EMPTY_SET;
             else {
                 _pcClassNames = new ArrayList(clss.size());
-                for (Iterator itr = clss.iterator(); itr.hasNext();)
-                    _pcClassNames.add(((Class) itr.next()).getName());
+                for (Iterator itr = clss.iterator(); itr.hasNext();) {
+                    Class cls = (Class) itr.next();
+                    _pcClassNames.add(cls.getName());
+                    if (needsSub(cls))
+                        toRedefine.add(cls);
+                }
                 _pcClassLoaders = new ReferenceHashSet(ReferenceHashSet.WEAK);
                 _pcClassLoaders.add(loader);
             }
-            return;
+        } else {
+            // reload with this loader
+            if (_pcClassLoaders.add(loader)) {
+                for (Iterator itr = _pcClassNames.iterator(); itr.hasNext();) {
+                    try {
+                        Class cls =
+                            Class.forName((String) itr.next(), true, loader);
+                        if (needsSub(cls))
+                            toRedefine.add(cls);
+                    } catch (Throwable t) {
+                        _conf.getLog(OpenJPAConfiguration.LOG_RUNTIME)
+                            .warn(null, t);
+                    }
+                }
+            }
         }
 
-        // reload with this loader
-        if (_pcClassLoaders.add(loader)) {
-            for (Iterator itr = _pcClassNames.iterator(); itr.hasNext();) {
-                try {
-                    Class.forName((String) itr.next(), true, loader);
-                } catch (Throwable t) {
-                    _conf.getLog(OpenJPAConfiguration.LOG_RUNTIME)
-                        .warn(null, t);
-                }
+        if (JavaVersions.VERSION >= 5) {
+            try {
+                // This is Java 5 / 6 code. There might be a more elegant
+                // way to bootstrap this into the system, but reflection
+                // will get things working for now. We could potentially
+                // do this by creating a new BrokerFactoryEvent type for
+                // Broker creation, at which point we have an appropriate
+                // classloader to use.
+                Class cls = Class.forName(
+                    "org.apache.openjpa.enhance.ManagedClassSubclasser");
+                cls.getMethod("prepareUnenhancedClasses", new Class[] {
+                        OpenJPAConfiguration.class, Collection.class,
+                        ClassLoader.class
+                    })
+                    .invoke(null, new Object[]{ _conf, toRedefine, envLoader });
+            } catch (NoSuchMethodException e) {
+                // should never happen in a properly-built installation
+                throw new InternalException(e);
+            } catch (IllegalAccessException e) {
+                // should never happen in a properly-built installation
+                throw new InternalException(e);
+            } catch (InvocationTargetException e) {
+                Throwable cause = e.getCause();
+                if (cause instanceof OpenJPAException)
+                    throw (OpenJPAException) cause;
+                else
+                    throw new InternalException(cause);
+            } catch (ClassNotFoundException e) {
+                // should never happen in a properly-built installation
+                throw new InternalException(e);
             }
         }
     }
 
+    private boolean needsSub(Class cls) {
+        return !cls.isInterface()
+            && !PersistenceCapable.class.isAssignableFrom(cls);
+    }
+
     public void addLifecycleListener(Object listener, Class[] classes) {
         lock();
         try {
@@ -477,7 +525,7 @@
      * current transaction, or returns null if none.
      */
     protected BrokerImpl findTransactionalBroker(String user, String pass) {
-        Transaction trans = null;
+        Transaction trans;
         try {
             trans = _conf.getManagedRuntimeInstance().getTransactionManager().
                 getTransaction();
@@ -626,7 +674,7 @@
      * failed objects in the nested exceptions.
      */
     private void assertNoActiveTransaction() {
-        Collection excs = null;
+        Collection excs;
         if (_transactional.isEmpty())
             return;
 
@@ -653,7 +701,7 @@
      * @return true if synched with transaction, false otherwise
      */
     boolean syncWithManagedTransaction(BrokerImpl broker, boolean begin) {
-        Transaction trans = null;
+        Transaction trans;
         try {
             TransactionManager tm = broker.getManagedRuntime().
                 getTransactionManager();

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachManager.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachManager.java Thu Jul 26 15:08:37 2007
@@ -39,6 +39,7 @@
 import org.apache.openjpa.util.OptimisticException;
 import org.apache.openjpa.util.ProxyManager;
 import org.apache.openjpa.util.UserException;
+import org.apache.openjpa.util.ImplHelper;
 
 /**
  * Handles attaching instances.
@@ -234,8 +235,9 @@
 
         //### need to handle ACT_RUN without also ACT_CASCADE
         ClassMetaData meta = _broker.getConfiguration().
-            getMetaDataRepositoryInstance().getMetaData(toAttach.getClass(),
-            _broker.getClassLoader(), true);
+            getMetaDataRepositoryInstance().getMetaData(
+                ImplHelper.getManagedInstance(toAttach).getClass(),
+                _broker.getClassLoader(), true);
         return getStrategy(toAttach).attach(this, toAttach, meta, into,
             owner, ownerMeta, explicit);
     }
@@ -254,7 +256,8 @@
      * Calculate proper attach strategy for instance.
      */
     private AttachStrategy getStrategy(Object toAttach) {
-        PersistenceCapable pc = (PersistenceCapable) toAttach;
+        PersistenceCapable pc = ImplHelper.toPersistenceCapable(toAttach,
+            getBroker().getConfiguration());
         if (pc.pcGetStateManager() instanceof AttachStrategy)
             return (AttachStrategy) pc.pcGetStateManager();
 
@@ -293,7 +296,8 @@
      * the (cached) attached copy.
      */
     PersistenceCapable getAttachedCopy(Object pc) {
-        return (PersistenceCapable) _attached.get(pc);
+        return ImplHelper.toPersistenceCapable(_attached.get(pc),
+            getBroker().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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -735,8 +735,6 @@
 
     /**
      * Fire given transaction event, handling any exceptions appropriately.
-     *
-     * @return whether events are being processed at this time
      */
     private void fireTransactionEvent(TransactionEvent trans) {
         if (_transEventManager != null)
@@ -792,7 +790,7 @@
                     // after making instance transactional for locking
                     if (!sm.isTransactional() && useTransactionalState(fetch))
                         sm.transactional();
-                    boolean loaded = false;
+                    boolean loaded;
                     try {
                         loaded = sm.load(fetch, StateManagerImpl.LOAD_FGS, 
                             exclude, edata, false);
@@ -4152,8 +4150,9 @@
 
     public Object getObjectId(Object obj) {
         assertOpen();
-        if (obj instanceof PersistenceCapable)
-            return ((PersistenceCapable) obj).pcFetchObjectId();
+        if (ImplHelper.isManageable(obj))
+            return (ImplHelper.toPersistenceCapable(obj, _conf))
+                .pcFetchObjectId();
         return null;
     }
 
@@ -4170,58 +4169,62 @@
 
     public Object getVersion(Object obj) {
         assertOpen();
-        if (obj instanceof PersistenceCapable)
-            return ((PersistenceCapable) obj).pcGetVersion();
+        if (ImplHelper.isManageable(obj))
+            return (ImplHelper.toPersistenceCapable(obj, _conf)).pcGetVersion();
         return null;
     }
 
     public boolean isDirty(Object obj) {
         assertOpen();
-        if (obj instanceof PersistenceCapable)
-            return ((PersistenceCapable) obj).pcIsDirty();
+        if (ImplHelper.isManageable(obj)) {
+            PersistenceCapable pc = ImplHelper.toPersistenceCapable(obj, _conf);
+            return pc.pcIsDirty();
+        }
         return false;
     }
 
     public boolean isTransactional(Object obj) {
         assertOpen();
-        if (obj instanceof PersistenceCapable)
-            return ((PersistenceCapable) obj).pcIsTransactional();
+        if (ImplHelper.isManageable(obj))
+            return (ImplHelper.toPersistenceCapable(obj, _conf))
+                .pcIsTransactional();
         return false;
     }
 
     public boolean isPersistent(Object obj) {
         assertOpen();
-        if (obj instanceof PersistenceCapable)
-            return ((PersistenceCapable) obj).pcIsPersistent();
+        if (ImplHelper.isManageable(obj))
+            return (ImplHelper.toPersistenceCapable(obj, _conf)).pcIsPersistent();
         return false;
     }
 
     public boolean isNew(Object obj) {
         assertOpen();
-        if (obj instanceof PersistenceCapable)
-            return ((PersistenceCapable) obj).pcIsNew();
+        if (ImplHelper.isManageable(obj))
+            return (ImplHelper.toPersistenceCapable(obj, _conf)).pcIsNew();
         return false;
     }
 
     public boolean isDeleted(Object obj) {
         assertOpen();
-        if (obj instanceof PersistenceCapable)
-            return ((PersistenceCapable) obj).pcIsDeleted();
+        if (ImplHelper.isManageable(obj))
+            return (ImplHelper.toPersistenceCapable(obj, _conf)).pcIsDeleted();
         return false;
     }
 
     public boolean isDetached(Object obj) {
-        if (!(obj instanceof PersistenceCapable))
+        if (!(ImplHelper.isManageable(obj)))
             return false;
 
-        PersistenceCapable pc = (PersistenceCapable) obj;
+        PersistenceCapable pc = ImplHelper.toPersistenceCapable(obj, _conf);
         Boolean detached = pc.pcIsDetached();
         if (detached != null)
             return detached.booleanValue();
 
         // last resort: instance is detached if it has a store record
         ClassMetaData meta = _conf.getMetaDataRepositoryInstance().
-            getMetaData(pc.getClass(), _loader, true);
+            getMetaData(ImplHelper.getManagedInstance(pc).getClass(),
+                _loader, true);
         Object oid = ApplicationIds.create(pc, meta);
         if (oid == null)
             return false;
@@ -4241,8 +4244,8 @@
      */
     protected StateManagerImpl getStateManagerImpl(Object obj,
         boolean assertThisContext) {
-        if (obj instanceof PersistenceCapable) {
-            PersistenceCapable pc = (PersistenceCapable) obj;
+        if (ImplHelper.isManageable(obj)) {
+            PersistenceCapable pc = ImplHelper.toPersistenceCapable(obj, _conf);
             if (pc.pcGetGenericContext() == this)
                 return (StateManagerImpl) pc.pcGetStateManager();
             if (assertThisContext && pc.pcGetGenericContext() != null)
@@ -4272,10 +4275,10 @@
     protected PersistenceCapable assertPersistenceCapable(Object obj) {
         if (obj == null)
             return null;
-        if (obj instanceof PersistenceCapable)
-            return (PersistenceCapable) obj;
+        if (ImplHelper.isManageable(obj))
+            return ImplHelper.toPersistenceCapable(obj, _conf);
 
-        // check for difference instances of the PersistenceCapable interface
+        // check for different instances of the PersistenceCapable interface
         // and throw a better error that mentions the class loaders
         Class[] intfs = obj.getClass().getInterfaces();
         for (int i = 0; intfs != null && i < intfs.length; i++) {
@@ -4373,6 +4376,7 @@
         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.
@@ -4449,6 +4453,12 @@
                     (orig.getManagedInstance()))).
                     setFailedObject(sm.getManagedInstance());
             }
+
+            if (!sm.isIntercepting()) {
+                if (_untracked == null)
+                    _untracked = new HashSet();
+                _untracked.add(sm);
+            }
         }
 
         /**
@@ -4471,12 +4481,15 @@
                             _conflicts.put(id, orig); // put back
                     }
                 }
-            } else
-            if ((_embeds == null || !_embeds.remove(sm)) && _news != null) {
+            } 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);
         }
 
         /**
@@ -4600,6 +4613,8 @@
                 _news.clear();
             if (_embeds != null)
                 _embeds.clear();
+            if (_untracked != null)
+                _untracked.clear();
         }
 
         /**

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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -28,6 +28,7 @@
 import org.apache.openjpa.util.ApplicationIds;
 import org.apache.openjpa.util.InternalException;
 import org.apache.openjpa.util.OptimisticException;
+import org.apache.openjpa.util.ImplHelper;
 
 /**
  * Handles attaching instances with detached state.
@@ -46,11 +47,13 @@
         if (toAttach == null)
             return null;
 
-        PersistenceCapable pc = (PersistenceCapable) toAttach;
         Broker broker = manager.getBroker();
+        PersistenceCapable pc = ImplHelper.toPersistenceCapable(toAttach,
+            broker.getConfiguration());
         ClassMetaData meta = broker.getConfiguration().
-            getMetaDataRepositoryInstance().getMetaData(toAttach.getClass(),
-            broker.getClassLoader(), true);
+            getMetaDataRepositoryInstance().getMetaData(
+                ImplHelper.getManagedInstance(toAttach).getClass(),
+                broker.getClassLoader(), true);
 
         switch (meta.getIdentityType()) {
             case ClassMetaData.ID_DATASTORE:
@@ -58,7 +61,7 @@
                 if (state == null)
                     return null;
                 return broker
-                    .newObjectId(toAttach.getClass(), (String) state[0]);
+                    .newObjectId(toAttach.getClass(), state[0]);
             case ClassMetaData.ID_APPLICATION:
                 return ApplicationIds.create(pc, meta);
             default:
@@ -68,14 +71,16 @@
 
     protected void provideField(Object toAttach, StateManagerImpl sm,
         int field) {
-        sm.provideField((PersistenceCapable) toAttach, this, field);
+        sm.provideField(ImplHelper.toPersistenceCapable(toAttach,
+            sm.getContext().getConfiguration()), this, field);
     }
 
     public Object attach(AttachManager manager, Object toAttach,
         ClassMetaData meta, PersistenceCapable into, OpenJPAStateManager owner,
         ValueMetaData ownerMeta, boolean explicit) {
         BrokerImpl broker = manager.getBroker();
-        PersistenceCapable pc = (PersistenceCapable) toAttach;
+        PersistenceCapable pc = ImplHelper.toPersistenceCapable(toAttach,
+            manager.getBroker().getConfiguration());
 
         Object[] state = (Object[]) pc.pcGetDetachedState();
         boolean embedded = ownerMeta != null && ownerMeta.isEmbeddedPC();
@@ -103,7 +108,9 @@
         } else if (!embedded && into == null) {
             Object id = getDetachedObjectId(manager, pc);
             if (id != null)
-                into = (PersistenceCapable) broker.find(id, true, null);
+                into =
+                    ImplHelper.toPersistenceCapable(broker.find(id, true, null),
+                        manager.getBroker().getConfiguration());
             if (into == null) {
                 // we mark objects that were new on detach by putting an empty
                 // extra element in their detached state array
@@ -114,7 +121,8 @@
                 // will throw an OVE if it was not PNEW when it was detached
                 if (!isNew)
                     throw new OptimisticException(_loc.get("attach-deleted",
-                        pc.getClass(), id)).setFailedObject(id);
+                        ImplHelper.getManagedInstance(pc).getClass(), id))
+                        .setFailedObject(id);
 
                 // if the instance does not exist, we assume that it was
                 // made persistent in a new transaction, detached, and then
@@ -185,6 +193,6 @@
                     break;
             }
         }
-        return into;
+        return ImplHelper.getManagedInstance(into);
     }
 }

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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -36,6 +36,7 @@
 import org.apache.openjpa.util.Exceptions;
 import org.apache.openjpa.util.Proxy;
 import org.apache.openjpa.util.UnsupportedException;
+import org.apache.openjpa.util.ImplHelper;
 
 /**
  * Internal state manager for detached instances. Does not fully
@@ -93,12 +94,13 @@
         ClassMetaData meta, PersistenceCapable into, OpenJPAStateManager owner,
         ValueMetaData ownerMeta, boolean explicit) {
         BrokerImpl broker = manager.getBroker();
-        StateManagerImpl sm = null;
+        StateManagerImpl sm;
         if (_embedded) {
             if (_dirty.length () > 0)
                 owner.dirty(ownerMeta.getFieldMetaData().getIndex());
             sm = (StateManagerImpl) broker.embed(_pc, _oid, owner, ownerMeta);
-            ((PersistenceCapable) toAttach).pcReplaceStateManager(this);
+            ImplHelper.toPersistenceCapable(toAttach, broker.getConfiguration())
+                .pcReplaceStateManager(this);
         } else {
             PCState state = (_dirty.length() > 0) ? PCState.PDIRTY
                 : PCState.PCLEAN;
@@ -161,8 +163,9 @@
             switch (fields[i].getDeclaredTypeCode()) {
                 case JavaTypes.BOOLEAN:
                     if (_dirty.get(i))
-                        sm.settingBooleanField(pc, i, (!loaded.get(i)) ? false
-                            : sm.fetchBooleanField(i), longval == 1, set);
+                        sm.settingBooleanField(pc, i,
+                            (loaded.get(i)) && sm.fetchBooleanField(i),
+                            longval == 1, set);
                     else
                         sm.storeBooleanField(i, longval == 1);
                     break;
@@ -231,7 +234,8 @@
                     else {
                         PersistenceCapable toPC = null;
                         if (objval != null && fields[i].isEmbeddedPC())
-                            toPC = (PersistenceCapable) objval;
+                            toPC = ImplHelper.toPersistenceCapable(objval,
+                                broker.getConfiguration());
                         objval = manager.attach(objval, toPC, sm, fields[i],
                             false);
                     }

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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -31,6 +31,7 @@
 import org.apache.openjpa.meta.ValueMetaData;
 import org.apache.openjpa.util.InternalException;
 import org.apache.openjpa.util.UnsupportedException;
+import org.apache.openjpa.util.ImplHelper;
 import serp.util.Numbers;
 
 /**
@@ -50,14 +51,15 @@
     private ClassMetaData _meta;
 
     public DetachedValueStateManager(Object pc, StoreContext ctx) {
-        this((PersistenceCapable) pc, ctx.getConfiguration().
-            getMetaDataRepositoryInstance().getMetaData(pc.getClass(),
+        this(ImplHelper.toPersistenceCapable(pc, ctx.getConfiguration()),
+            ctx.getConfiguration().getMetaDataRepositoryInstance()
+                .getMetaData(ImplHelper.getManagedInstance(pc).getClass(),
             ctx.getClassLoader(), true), ctx);
     }
 
     public DetachedValueStateManager(PersistenceCapable pc, ClassMetaData meta,
         StoreContext ctx) {
-        _pc = (PersistenceCapable) pc;
+        _pc = ImplHelper.toPersistenceCapable(pc, ctx.getConfiguration());
         _meta = meta;
         _ctx = ctx;
     }

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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -35,6 +35,7 @@
 import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.meta.ValueMetaData;
 import org.apache.openjpa.util.GeneralException;
+import org.apache.openjpa.util.ImplHelper;
 import serp.util.Numbers;
 
 /**
@@ -296,7 +297,8 @@
     }
 
     public PersistenceCapable getPersistenceCapable() {
-        return (PersistenceCapable) _oid;
+        return ImplHelper.toPersistenceCapable(_oid,
+            _vmd.getRepository().getConfiguration());
     }
 
     public ClassMetaData getMetaData() {

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java Thu Jul 26 15:08:37 2007
@@ -61,6 +61,7 @@
 import org.apache.openjpa.util.OpenJPAException;
 import org.apache.openjpa.util.UnsupportedException;
 import org.apache.openjpa.util.UserException;
+import org.apache.openjpa.util.ImplHelper;
 import serp.util.Numbers;
 import serp.util.Strings;
 
@@ -1083,7 +1084,8 @@
 
             OpenJPAStateManager sm = _broker.getStateManager(ob);
             int i = fmd.getIndex();
-            PersistenceCapable into = (PersistenceCapable) ob;
+            PersistenceCapable into = ImplHelper.toPersistenceCapable(ob,
+                _broker.getConfiguration());
 
             // set the actual field in the instance
             int set = OpenJPAStateManager.SET_USER;

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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -24,6 +24,7 @@
 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;
@@ -33,7 +34,7 @@
  *
  * @author Abe White
  */
-class SaveFieldManager
+public class SaveFieldManager
     extends ClearFieldManager {
 
     private final StateManagerImpl _sm;
@@ -88,7 +89,7 @@
      */
     public boolean saveField(int field) {
         // if not loaded we can't save orig value; mark as unloaded on rollback
-        if (!_sm.getLoaded().get(field)) {
+        if (_sm.getLoaded() != null && !_sm.getLoaded().get(field)) {
             _unloaded.set(field);
             return false;
         }
@@ -165,6 +166,24 @@
         _copyField[0] = field;
         _sm.getPersistenceCapable().pcCopyFields(_state, _copyField);
         return false;
+    }
+
+    /**
+     * Compare the given field.
+     * @return <code>true</code> if the field is the same in the current
+     * state and in the saved state; otherwise, <code>false</code>.
+     */
+    public boolean isFieldEqual(int field, Object current) {
+        // if the field is not available, assume that it has changed.
+        if (_saved == null || !_saved.get(field))
+            return false;
+        if (!(_state.pcGetStateManager() instanceof OpenJPAStateManager))
+            return false;
+
+        OpenJPAStateManager sm = (OpenJPAStateManager)
+            _state.pcGetStateManager();
+        Object old = sm.fetch(field);
+        return current == old || current != null && current.equals(old);
     }
 
     public Object fetchObjectField(int field) {

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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -29,6 +29,8 @@
 import org.apache.openjpa.enhance.PCRegistry;
 import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.enhance.StateManager;
+import org.apache.openjpa.enhance.ManagedInstanceProvider;
+import org.apache.openjpa.enhance.DynamicPersistenceCapable;
 import org.apache.openjpa.event.LifecycleEvent;
 import org.apache.openjpa.event.LifecycleEventManager;
 import org.apache.openjpa.lib.util.Localizer;
@@ -48,6 +50,7 @@
 import org.apache.openjpa.util.ProxyManager;
 import org.apache.openjpa.util.RuntimeExceptionTranslator;
 import org.apache.openjpa.util.UserException;
+import org.apache.openjpa.util.ImplHelper;
 import serp.util.Numbers;
 
 /**
@@ -89,7 +92,7 @@
     private static final int FLAG_VERSION_UPDATE = 2 << 15;
     private static final int FLAG_DETACHING = 2 << 16;
 
-    private static Localizer _loc = Localizer.forPackage
+    private static final Localizer _loc = Localizer.forPackage
         (StateManagerImpl.class);
 
     // information about the instance
@@ -300,6 +303,27 @@
         _broker.setStateManager(_id, this, BrokerImpl.STATUS_INIT);
         if (state == PCState.PNEW)
             fireLifecycleEvent(LifecycleEvent.AFTER_PERSIST);
+
+        // if this is a non-tracking PC, add a hard ref to the appropriate data
+        // sets and give it an opportunity to make a state snapshot.
+        if (!isIntercepting())
+            saveFields(true);
+    }
+
+    /**
+     * Whether or not data access in this instance is intercepted. This differs
+     * from {@link ClassMetaData#isIntercepting()} in that it checks for
+     * property access + subclassing in addition to the redefinition /
+     * enhancement checks.
+     */
+    public boolean isIntercepting() {
+        if (getMetaData().isIntercepting())
+            return true;
+        if (getMetaData().getAccessType() != ClassMetaData.ACCESS_FIELD
+            && _pc instanceof DynamicPersistenceCapable)
+            return true;
+
+        return false;
     }
 
     /**
@@ -339,7 +363,10 @@
     }
 
     public Object getManagedInstance() {
-        return _pc;
+        if (_pc instanceof ManagedInstanceProvider)
+            return ((ManagedInstanceProvider) _pc).getManagedInstance();
+        else
+            return _pc;
     }
 
     public PersistenceCapable getPersistenceCapable() {
@@ -735,6 +762,61 @@
         storeField(field, val, this);
     }
 
+    /**
+     * <p>Checks whether or not <code>_pc</code> is dirty. In the cases where
+     * field tracking is not happening (see below), this method will do a
+     * state comparison to find whether <code>_pc</code> is dirty, and will
+     * update this instance with this information. In the cases where field
+     * tracking is happening, this method is a no-op.</p>
+     *
+     * <p>Fields are tracked for all classes that are run through the OpenJPA
+     * enhancer prior to or during deployment, and all classes (enhanced or
+     * unenhanced) in a Java 6 environment or newer.</p>
+     *
+     * <p>In a Java 5 VM or older:
+     * <br>- instances of unenhanced classes that use
+     * property access and obey the property access limitations are tracked
+     * when the instances are loaded from the database by OpenJPA, and are
+     * not tracked when the instances are created by application code.
+     * <br>- instances of unenhanced classes that use field access are
+     * never tracked.</p>
+     *
+     * @since 1.0.0
+     */
+    public void dirtyCheck() {
+        if (!needsDirtyCheck())
+            return;
+
+        SaveFieldManager saved = getSaveFieldManager();
+        if (saved == null)
+            throw new InternalException(_loc.get("no-saved-fields"));
+
+        FieldMetaData[] fmds = getMetaData().getFields();
+        for (int i = 0; i < fmds.length; i++) {
+            // pk and version fields cannot be mutated; don't mark them
+            // as such. ##### validate?
+            if (!fmds[i].isPrimaryKey()
+                && !fmds[i].isVersion()) {
+                if (!saved.isFieldEqual(i, fetch(i))) {
+                    dirty(i);
+                }
+            }
+        }
+    }
+
+    private boolean needsDirtyCheck() {
+        if (isIntercepting())
+            return false;
+        if (isDeleted())
+            return false;
+        if (isNew() && !isFlushed())
+            return false;
+        if (getMetaData().getAccessType() != ClassMetaData.ACCESS_FIELD
+            && !(isNew() && isFlushed()))
+            return false;
+        return true;
+    }
+
     public Object fetchInitialField(int field) {
         FieldMetaData fmd = _meta.getField(field);
         if (_broker.getRestoreState() == RestoreState.RESTORE_NONE
@@ -1375,7 +1457,8 @@
         FieldMetaData fmd = _meta.getField(field);
         if (fmd == null)
             throw translate(new UserException(_loc.get("no-field", field,
-                _pc.getClass())).setFailedObject(getManagedInstance()));
+                ImplHelper.getManagedInstance(_pc).getClass()))
+                .setFailedObject(getManagedInstance()));
 
         dirty(fmd.getIndex(), null, true);
     }
@@ -1505,7 +1588,7 @@
     /**
      * Fire post-dirty events after field value changes.
      *
-     * @param status return value from {@link #dirty(int,boolean,boolean)}
+     * @param status return value from {@link #dirty(int, Boolean, boolean)}
      */
     private void postDirty(Boolean status) {
         if (Boolean.TRUE.equals(status))
@@ -1836,7 +1919,8 @@
      */
     void assertNotManagedObjectId(Object val) {
         if (val != null
-            && ((PersistenceCapable) val).pcGetGenericContext() != null)
+            && (ImplHelper.toPersistenceCapable(val,
+                 getContext().getConfiguration())).pcGetGenericContext()!= null)
             throw translate(new InvalidStateException(_loc.get
                 ("managed-oid", Exceptions.toString(val),
                     Exceptions.toString(getManagedInstance()))).
@@ -2486,6 +2570,9 @@
      * are not cleared.
      */
     void clearFields() {
+        if (!isIntercepting())
+            return;
+
         fireLifecycleEvent(LifecycleEvent.BEFORE_CLEAR);
 
         // unproxy all fields
@@ -2569,8 +2656,14 @@
      * to that of the last call to {@link #saveFields}.
      */
     void clearSavedFields() {
-        _flags &= ~FLAG_SAVE;
-        _saved = null;
+        if (isIntercepting()) {
+            _flags &= ~FLAG_SAVE;
+            _saved = null;
+        }
+    }
+
+    public SaveFieldManager getSaveFieldManager() {
+        return _saved;
     }
 
     /**
@@ -2681,6 +2774,8 @@
                         _single.clear();
                 }
             }
+
+            dirtyCheck();
         } finally {
             unlock();
         }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java Thu Jul 26 15:08:37 2007
@@ -177,7 +177,7 @@
      * several objects. Each of the given state managers will be in one of
      * three states, each requiring a different action:
      * <ul>
-     * <li><code>stateManager.getManagedInstance () == null</code>: An
+     * <li><code>stateManager.getO () == null</code>: An
      * uninitialized state manager. Perform the same actions as in
      * {@link #initialize}.
      * <li><code>load != FORCE_LOAD_NONE || stateManager.getPCState ()

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/VersionAttachStrategy.java Thu Jul 26 15:08:37 2007
@@ -32,6 +32,7 @@
 import org.apache.openjpa.util.ApplicationIds;
 import org.apache.openjpa.util.ObjectNotFoundException;
 import org.apache.openjpa.util.OptimisticException;
+import org.apache.openjpa.util.ImplHelper;
 
 /**
  * Handles attaching instances using version and primary key fields.
@@ -50,26 +51,31 @@
         Object toAttach) {
         Broker broker = manager.getBroker();
         ClassMetaData meta = broker.getConfiguration().
-            getMetaDataRepositoryInstance().getMetaData(toAttach.getClass(),
-            broker.getClassLoader(), true);
-        return ApplicationIds.create((PersistenceCapable) toAttach, meta);
+            getMetaDataRepositoryInstance().getMetaData(
+                ImplHelper.getManagedInstance(toAttach).getClass(),
+                broker.getClassLoader(), true);
+        return ApplicationIds.create(ImplHelper.toPersistenceCapable(toAttach,
+            broker.getConfiguration()),
+            meta);
     }
 
     protected void provideField(Object toAttach, StateManagerImpl sm,
         int field) {
-        sm.provideField((PersistenceCapable) toAttach, this, field);
+        sm.provideField(ImplHelper.toPersistenceCapable(toAttach,
+            sm.getContext().getConfiguration()), this, field);
     }
 
     public Object attach(AttachManager manager, Object toAttach,
         ClassMetaData meta, PersistenceCapable into, OpenJPAStateManager owner,
         ValueMetaData ownerMeta, boolean explicit) {
         BrokerImpl broker = manager.getBroker();
-        PersistenceCapable pc = (PersistenceCapable) toAttach;
+        PersistenceCapable pc = ImplHelper.toPersistenceCapable(toAttach,
+            meta.getRepository().getConfiguration());
 
         boolean embedded = ownerMeta != null && ownerMeta.isEmbeddedPC();
         boolean isNew = !broker.isDetached(pc);
         Object version = null;
-        StateManagerImpl sm = null;
+        StateManagerImpl sm;
 
         // if the state manager for the embedded instance is null, then
         // it should be treated as a new instance (since the
@@ -91,10 +97,13 @@
         } else if (!embedded && into == null) {
             Object id = getDetachedObjectId(manager, toAttach);
             if (id != null)
-                into = (PersistenceCapable) broker.find(id, true, null);
+                into =
+                    ImplHelper.toPersistenceCapable(broker.find(id, true, null),
+                        broker.getConfiguration());
             if (into == null)
                 throw new OptimisticException(_loc.get("attach-version-del",
-                    pc.getClass(), id, version)).setFailedObject(toAttach);
+                    ImplHelper.getManagedInstance(pc).getClass(), id, version))
+                    .setFailedObject(toAttach);
 
             sm = manager.assertManaged(into);
             if (meta.getDescribedType()
@@ -148,7 +157,7 @@
         }
         if (!embedded && !isNew)
             compareVersion(sm, pc);
-        return into;
+        return ImplHelper.getManagedInstance(into);
     }
 
     /**

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/CandidatePath.java Thu Jul 26 15:08:37 2007
@@ -23,7 +23,6 @@
 import java.util.ListIterator;
 
 import org.apache.commons.lang.ObjectUtils;
-import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.kernel.Broker;
 import org.apache.openjpa.kernel.Filters;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
@@ -31,6 +30,7 @@
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
 import org.apache.openjpa.meta.XMLMetaData;
+import org.apache.openjpa.util.ImplHelper;
 
 /**
  * A path represents a traversal into fields of a candidate object.
@@ -126,8 +126,9 @@
             // be proxyable
             sm = null;
             tmpBroker = null;
-            if (candidate instanceof PersistenceCapable)
-                sm = (OpenJPAStateManager) ((PersistenceCapable) candidate).
+            if (ImplHelper.isManageable(candidate))
+                sm = (OpenJPAStateManager) (ImplHelper.toPersistenceCapable(
+                    candidate, ctx.getConfiguration())).
                     pcGetStateManager();
             if (sm == null) {
                 tmpBroker = ctx.getBroker();

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java Thu Jul 26 15:08:37 2007
@@ -39,8 +39,8 @@
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.datacache.DataCache;
 import org.apache.openjpa.enhance.PCRegistry;
-import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.enhance.Reflection;
+import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.lib.log.Log;
 import org.apache.openjpa.lib.meta.SourceTracker;
 import org.apache.openjpa.lib.util.J2DoPrivHelper;
@@ -61,6 +61,7 @@
 import org.apache.openjpa.util.ShortId;
 import org.apache.openjpa.util.StringId;
 import org.apache.openjpa.util.UnsupportedException;
+import org.apache.openjpa.util.ImplHelper;
 import serp.util.Strings;
 
 /**
@@ -184,6 +185,7 @@
     private FieldMetaData[] _allListingFields = null;
     private FetchGroup[] _fgs = null;
     private FetchGroup[] _customFGs = null;
+    private boolean _intercepting = false;
 
     /**
      * Constructor. Supply described type and repository.
@@ -234,6 +236,8 @@
             (type.getSuperclass().getName()))
             throw new MetaDataException(_loc.get("enum", type));
         _type = type;
+        if (PersistenceCapable.class.isAssignableFrom(type))
+            setIntercepting(true);
     }
 
     /**
@@ -689,6 +693,22 @@
     }
 
     /**
+     * Whether the type's fields are actively intercepted, either by
+     * redefinition or enhancement.
+     */
+    public boolean isIntercepting() {
+        return _intercepting;
+    }
+
+    /**
+     * Whether the type's fields are actively intercepted, either by
+     * redefinition or enhancement.
+     */
+    public void setIntercepting(boolean intercepting) {
+        _intercepting = intercepting;
+    }
+
+    /**
      * Whether the type is a managed interface.
      */
     public boolean isManagedInterface() {
@@ -1576,7 +1596,10 @@
 
         int val = _repos.getValidate();
         boolean runtime = (val & _repos.VALIDATE_RUNTIME) != 0;
-        boolean validate = !PersistenceCapable.class.isAssignableFrom(_type)
+        // ##### what to do here? This should essentially never fail anymore.
+        // ##### Maybe remove altogether?
+        boolean validate =
+            !ImplHelper.isManagedType(_type)
             || (val & MetaDataRepository.VALIDATE_UNENHANCED) == 0;
 
         // we only do any actions for metadata mode
@@ -1605,8 +1628,10 @@
             log.trace(_loc.get((embed) ? "resolve-embed-meta" : "resolve-meta",
                 this + "@" + System.identityHashCode(this)));
 
-        if (runtime && !_type.isInterface() && 
-            !PersistenceCapable.class.isAssignableFrom(_type))
+        // ##### what to do here? This should essentially never fail anymore.
+        // ##### either remove, or convert to warning.
+        if (runtime && !_type.isInterface() &&
+            !ImplHelper.isManagedType(_type))
             throw new MetaDataException(_loc.get("not-enhanced", _type));
 
         // are we the target of an embedded value?
@@ -1710,7 +1735,7 @@
         validateDataCache();
         validateDetachable();
         validateExtensionKeys();
-        validateIdentity(runtime);
+        validateIdentity();
         validateAccessType();
     }
 
@@ -1769,7 +1794,7 @@
     /**
      * Assert that the identity handling for this class is valid.
      */
-    private void validateIdentity(boolean runtime) {
+    private void validateIdentity() {
         // make sure identity types are consistent
         ClassMetaData sup = getPCSuperclassMetaData();
         int id = getIdentityType();
@@ -1793,7 +1818,7 @@
         if (id == ID_APPLICATION) {
             if (_idStrategy != ValueStrategies.NONE)
                 throw new MetaDataException(_loc.get("appid-strategy", _type));
-            validateAppIdClass(runtime);
+            validateAppIdClass();
         } else if (id != ID_UNKNOWN)
             validateNoPKFields();
 
@@ -1809,7 +1834,7 @@
     /**
      * Make sure the application identity class is valid.
      */
-    private void validateAppIdClass(boolean runtime) {
+    private void validateAppIdClass() {
         // base types must declare an oid class if not single-field identity
         FieldMetaData[] pks = getPrimaryKeyFields();
         if (getObjectIdType() == null) {

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java Thu Jul 26 15:08:37 2007
@@ -47,7 +47,6 @@
 import org.apache.commons.collections.comparators.ComparatorChain;
 import org.apache.commons.lang.StringUtils;
 import org.apache.openjpa.conf.OpenJPAConfiguration;
-import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.kernel.StoreContext;
 import org.apache.openjpa.lib.conf.Configurations;
@@ -62,6 +61,7 @@
 import org.apache.openjpa.util.MetaDataException;
 import org.apache.openjpa.util.OpenJPAException;
 import org.apache.openjpa.util.UnsupportedException;
+import org.apache.openjpa.util.ImplHelper;
 import serp.util.Strings;
 
 /**
@@ -174,8 +174,9 @@
     // Members aren't serializable. Use a proxy that can provide a Member
     // to avoid writing the full Externalizable implementation.
     private transient MemberProvider _backingMember = null;
+    private String _backingFieldName = null;
     
-    // Members aren't serializable. Initializing _extMethod and _factMethod to 
+    // Members aren't serializable. Initializing _extMethod and _factMethod to
     // DEFAULT_METHOD is sufficient to trigger lazy population of these fields.
     private transient Method _extMethod = DEFAULT_METHOD;
     private transient Member _factMethod = DEFAULT_METHOD;
@@ -1586,9 +1587,11 @@
 
         MetaDataRepository repos = getRepository();
         int validate = repos.getValidate();
+        // ##### what to do here? This should essentially never fail anymore.
+        // ##### Maybe remove the isManagedType check.
         if ((validate & MetaDataRepository.VALIDATE_META) != 0
-            && (!PersistenceCapable.class.isAssignableFrom
-            (_owner.getDescribedType())
+            && (!ImplHelper
+            .isManagedType(_owner.getDescribedType())
             || (validate & MetaDataRepository.VALIDATE_UNENHANCED) == 0)) {
             validateLRS();
             if ((validate & repos.VALIDATE_RUNTIME) == 0)

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InMemoryRelatedFieldOrder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InMemoryRelatedFieldOrder.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InMemoryRelatedFieldOrder.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InMemoryRelatedFieldOrder.java Thu Jul 26 15:08:37 2007
@@ -22,6 +22,8 @@
 
 import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.util.ImplHelper;
 
 /**
  * Order by a field in the related type in memory.
@@ -33,10 +35,13 @@
 
     private final FieldMetaData _rel;
     private final boolean _asc;
+    private final OpenJPAConfiguration _conf;
 
-    public InMemoryRelatedFieldOrder(FieldMetaData rel, boolean asc) {
+    public InMemoryRelatedFieldOrder(FieldMetaData rel, boolean asc,
+        OpenJPAConfiguration conf) {
         _rel = rel;
         _asc = asc;
+        _conf = conf;
     }
 
     public String getName() {
@@ -54,12 +59,12 @@
     public int compare(Object o1, Object o2) {
         if (o1 == o2)
             return 0;
-        if (!(o1 instanceof PersistenceCapable)
-            || !(o2 instanceof PersistenceCapable))
+        if (!(ImplHelper.isManageable(o1))
+            || !(ImplHelper.isManageable(o2)))
             return 0;
 
-        PersistenceCapable pc1 = (PersistenceCapable) o1;
-        PersistenceCapable pc2 = (PersistenceCapable) o2;
+        PersistenceCapable pc1 = ImplHelper.toPersistenceCapable(o1, _conf);
+        PersistenceCapable pc2 = ImplHelper.toPersistenceCapable(o2, _conf);
         OpenJPAStateManager sm1 = (OpenJPAStateManager) pc1.pcGetStateManager();
         OpenJPAStateManager sm2 = (OpenJPAStateManager) pc2.pcGetStateManager();
         if (sm1 == null || sm2 == null)

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InMemoryValueOrder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InMemoryValueOrder.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InMemoryValueOrder.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InMemoryValueOrder.java Thu Jul 26 15:08:37 2007
@@ -23,6 +23,8 @@
 import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.util.ApplicationIds;
+import org.apache.openjpa.util.ImplHelper;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
 
 /**
  * Order by the field value in memory. If the field contains
@@ -36,9 +38,11 @@
     implements Order, Comparator {
 
     private final boolean _asc;
+    private final OpenJPAConfiguration _conf;
 
-    public InMemoryValueOrder(boolean asc) {
+    public InMemoryValueOrder(boolean asc, OpenJPAConfiguration conf) {
         _asc = asc;
+        _conf = conf;
     }
 
     public String getName() {
@@ -63,15 +67,15 @@
 
         // non-pc values must be comparable
         int cmp;
-        if (!(o1 instanceof PersistenceCapable)
-            || !(o2 instanceof PersistenceCapable)) {
+        if (!(ImplHelper.isManageable(o1))
+            || !(ImplHelper.isManageable(o2))) {
             cmp = ((Comparable) o1).compareTo(o2);
             return (_asc) ? cmp : -cmp;
         }
 
         // order on primary key values
-        PersistenceCapable pc1 = (PersistenceCapable) o1;
-        PersistenceCapable pc2 = (PersistenceCapable) o2;
+        PersistenceCapable pc1 = ImplHelper.toPersistenceCapable(o1, _conf);
+        PersistenceCapable pc2 = ImplHelper.toPersistenceCapable(o2, _conf);
         OpenJPAStateManager sm1 = (OpenJPAStateManager) pc1.pcGetStateManager();
         OpenJPAStateManager sm2 = (OpenJPAStateManager) pc2.pcGetStateManager();
         if (sm1 == null || sm2 == null)

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java Thu Jul 26 15:08:37 2007
@@ -38,6 +38,7 @@
 import org.apache.openjpa.enhance.PCRegistry;
 import org.apache.openjpa.enhance.PCRegistry.RegisterClassListener;
 import org.apache.openjpa.enhance.PersistenceCapable;
+import org.apache.openjpa.enhance.DynamicPersistenceCapable;
 import org.apache.openjpa.event.LifecycleEventManager;
 import org.apache.openjpa.lib.conf.Configurable;
 import org.apache.openjpa.lib.conf.Configuration;
@@ -48,6 +49,7 @@
 import org.apache.openjpa.util.InternalException;
 import org.apache.openjpa.util.MetaDataException;
 import org.apache.openjpa.util.OpenJPAId;
+import org.apache.openjpa.util.ImplHelper;
 import serp.util.Strings;
 
 /**
@@ -274,9 +276,14 @@
      */
     public synchronized ClassMetaData getMetaData(Class cls,
         ClassLoader envLoader, boolean mustExist) {
+        if (cls != null &&
+            DynamicPersistenceCapable.class.isAssignableFrom(cls))
+            cls = cls.getSuperclass();
+
         ClassMetaData meta = getMetaDataInternal(cls, envLoader);
         if (meta == null && mustExist) {
-            if (cls != null && !PersistenceCapable.class.isAssignableFrom(cls))
+            if (cls != null &&
+                !ImplHelper.isManagedType(cls))
                 throw new MetaDataException(_loc.get("no-meta-notpc", cls)).
                     setFatal(false);
 
@@ -824,7 +831,7 @@
      * Order by the field value.
      */
     protected Order newValueOrder(FieldMetaData owner, boolean asc) {
-        return new InMemoryValueOrder(asc);
+        return new InMemoryValueOrder(asc, getConfiguration());
     }
 
     /**
@@ -832,7 +839,7 @@
      */
     protected Order newRelatedFieldOrder(FieldMetaData owner,
         FieldMetaData rel, boolean asc) {
-        return new InMemoryRelatedFieldOrder(rel, asc);
+        return new InMemoryRelatedFieldOrder(rel, asc, getConfiguration());
     }
 
     /**

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Exceptions.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Exceptions.java?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Exceptions.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Exceptions.java Thu Jul 26 15:08:37 2007
@@ -249,10 +249,13 @@
      * <code>null</code> otherwise.
      */
     private static Object getObjectId(Object ob) {
-        if (ob instanceof PersistenceCapable
-            && !((PersistenceCapable) ob).pcIsNew())
-            return ((PersistenceCapable) ob).pcFetchObjectId();
+        if (!ImplHelper.isManageable(ob))
+            return null;
+
+        PersistenceCapable pc = ImplHelper.toPersistenceCapable(ob, null);
+        if (pc == null || pc.pcIsNew())
+            return null;
         else
-			return null;
+            return pc.pcFetchObjectId();
 	}
 }

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneratedClasses.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneratedClasses.java?view=auto&rev=560016
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneratedClasses.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneratedClasses.java Thu Jul 26 15:08:37 2007
@@ -0,0 +1,75 @@
+/*
+ * 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.util;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.lang.reflect.Constructor;
+
+import org.apache.openjpa.lib.util.J2DoPrivHelper;
+import org.apache.openjpa.lib.util.Localizer;
+import serp.bytecode.BCClass;
+import serp.bytecode.BCClassLoader;
+
+/**
+ * Utility methods when generating classes, including at runtime.
+ *
+ * @since 1.0.0
+ */
+public class GeneratedClasses {
+
+    /**
+     * Return the more derived loader of the class laoders for the given 
+     * classes.
+     */
+    public static ClassLoader getMostDerivedLoader(Class c1, Class c2) {
+        ClassLoader l1 = (ClassLoader) AccessController.doPrivileged(
+            J2DoPrivHelper.getClassLoaderAction(c1));
+        ClassLoader l2 = (ClassLoader) AccessController.doPrivileged(
+            J2DoPrivHelper.getClassLoaderAction(c2));
+        if (l1 == l2)
+            return l1;
+        if (l1 == null)
+            return l2;
+        if (l2 == null)
+            return l1;
+
+        for (ClassLoader p = (ClassLoader) AccessController.doPrivileged(
+                J2DoPrivHelper.getParentAction(l1)); p != null;
+                p = (ClassLoader) AccessController.doPrivileged(
+                    J2DoPrivHelper.getParentAction(p)))
+            if (p == l2)
+                return l1;
+        return l2;
+    }
+
+    /**
+     * Load the class represented by the given bytecode.
+     */
+    public static Class loadBCClass(BCClass bc, ClassLoader loader) {
+        BCClassLoader bcloader = new BCClassLoader(bc.getProject(), loader);
+        try {
+            Class c = Class.forName(bc.getName(), true, bcloader);
+            bc.getProject().clear();
+            return c;
+        } catch (Throwable t) {
+            throw new GeneralException(bc.getName()).setCause(t);
+        }
+    }
+}

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?view=diff&rev=560016&r1=560015&r2=560016
==============================================================================
--- 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 Thu Jul 26 15:08:37 2007
@@ -26,6 +26,10 @@
 import java.util.Map;
 
 import org.apache.openjpa.enhance.PersistenceCapable;
+import org.apache.openjpa.enhance.PCRegistry;
+import org.apache.openjpa.enhance.StateManager;
+import org.apache.openjpa.enhance.ManagedInstanceProvider;
+import org.apache.openjpa.enhance.ReflectingPersistenceCapable;
 import org.apache.openjpa.kernel.FetchConfiguration;
 import org.apache.openjpa.kernel.LockManager;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
@@ -42,6 +46,7 @@
 import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.meta.SequenceMetaData;
 import org.apache.openjpa.meta.ValueStrategies;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
 
 /**
  * Helper for OpenJPA back-ends.
@@ -53,9 +58,32 @@
 public class ImplHelper {
 
     // Cache for from/to type assignments
-    private static ConcurrentReferenceHashMap _assignableTypes =
+    private static final Map _assignableTypes =
         new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD);
 
+    // map of all new unenhanced instances active in this classloader
+    public static final Map _unenhancedInstanceMap =
+        new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD) {
+
+            protected boolean eq(Object x, Object y) {
+                // the Entries in ConcurrentReferenceHashMap delegate back to
+                // eq() in their equals() impls
+                if (x instanceof Map.Entry)
+                    return super.eq(x, y);
+                else
+                    return x == y;
+            }
+
+            protected int hc(Object o) {
+                // the Entries in ConcurrentReferenceHashMap delegate back to
+                // hc() in their hashCode() impls
+                if (o instanceof Map.Entry)
+                    return super.hc(o);
+                else
+                    return System.identityHashCode(o);
+            }
+        };
+
     /**
      * Helper for store manager implementations. This method simply delegates
      * to the proper singular method for each state manager.
@@ -185,7 +213,8 @@
      * @return true if the class is manageable.
      */
     public static boolean isManagedType(Class type) {
-        return PersistenceCapable.class.isAssignableFrom(type);
+        return PersistenceCapable.class.isAssignableFrom(type)
+            || type != null && PCRegistry.isRegistered(type);
     }
 
     /**
@@ -195,7 +224,8 @@
      * @return true if the instance is a persistent type, false otherwise
      */
     public static boolean isManageable(Object instance) {
-        return instance instanceof PersistenceCapable;
+        return instance instanceof PersistenceCapable
+            || instance != null && PCRegistry.isRegistered(instance.getClass());
     }
 
     /**
@@ -226,5 +256,56 @@
         }
 
         return isAssignable.booleanValue();
+    }
+
+    /**
+     * @return the persistence-capable instance responsible for managing
+     * <code>o</code>, or <code>null</code> if <code>o</code> is not manageable.
+     * @since 1.0.0
+     */
+    public static PersistenceCapable toPersistenceCapable(Object o, Object ctx){
+        if (o instanceof PersistenceCapable)
+            return (PersistenceCapable) o;
+
+        OpenJPAConfiguration conf = null;
+        if (ctx instanceof OpenJPAConfiguration)
+            conf = (OpenJPAConfiguration) ctx;
+        else if (ctx instanceof StateManager
+            && ((StateManager) ctx).getGenericContext() instanceof StoreContext)
+            conf = ((StoreContext) ((StateManager) ctx).getGenericContext())
+                .getConfiguration();
+
+        if (!isManageable(o))
+            return null;
+
+        // if we had a putIfAbsent() method, we wouldn't need to sync here
+        synchronized (o) {
+            PersistenceCapable pc = (PersistenceCapable)
+                _unenhancedInstanceMap.get(o);
+
+            if (pc != null)
+                return pc;
+
+            // if we don't have a conf passed in, then we can't create a new
+            // ReflectingPC; this will only be the case when invoked from a
+            // context outside of OpenJPA.
+            if (conf == null)
+                return null;
+
+            pc = new ReflectingPersistenceCapable(o, conf);
+            _unenhancedInstanceMap.put(o, pc);
+            return pc;
+        }
+    }
+
+    /**
+     * @return the user-visible representation of <code>o</code>.
+     * @since 1.0.0
+     */
+    public static Object getManagedInstance(Object o) {
+        if (o instanceof ManagedInstanceProvider)
+            return ((ManagedInstanceProvider) o).getManagedInstance();
+        else
+            return o;
     }
 }



Mime
View raw message