You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by aw...@apache.org on 2006/11/04 00:15:10 UTC

svn commit: r471045 [1/2] - in /incubator/openjpa/trunk: 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-jd...

Author: awhite
Date: Fri Nov  3 15:15:08 2006
New Revision: 471045

URL: http://svn.apache.org/viewvc?view=rev&rev=471045
Log:
Support many-one and one-one relations as primary key fields.


Added:
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/BasicEntity.java   (with props)
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/DataStoreBasicEntity.java   (with props)
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/DataStoreManyOneIdOwner.java   (with props)
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ManyOneCompoundIdOwner.java   (with props)
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ManyOneCompoundIdOwnerId.java
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ManyOneIdOwner.java   (with props)
    incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestManyOneAsId.java
Modified:
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Joinable.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerFieldStrategy.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/IdentityJoinable.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/PrimitiveFieldStrategy.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StringFieldStrategy.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/schemas-doctype.rsrc
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/StateManager.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ProxySetupStateManager.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
    incubator/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java
    incubator/openjpa/trunk/openjpa-project/src/doc/manual/jpa_overview_pc.xml
    incubator/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml
    incubator/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GetObjectId.java Fri Nov  3 15:15:08 2006
@@ -114,16 +114,16 @@
         while (!mapping.isPrimaryKeyObjectId(false))
             mapping = mapping.getJoinablePCSuperclassMapping();
 
-        // relies on single-column primary key field mappings
         Column[] cols = mapping.getPrimaryKeyColumns();
-        Object[] ordered = new Object[cols.length];
+        Object[] vals = new Object[cols.length];
         Joinable join;
         for (int i = 0; i < cols.length; i++) {
             join = mapping.assertJoinable(cols[i]);
-            ordered[i] = pks[mapping.getField(join.getFieldIndex()).
+            vals[i] = pks[mapping.getField(join.getFieldIndex()).
                 getPrimaryKeyIndex()];
+            vals[i] = join.getJoinValue(vals[i], cols[i], ctx.store);
         }
-        return ordered;
+        return vals;
     }
 
     public void select(Select sel, ExpContext ctx, ExpState state, 

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java Fri Nov  3 15:15:08 2006
@@ -180,7 +180,7 @@
             if (vals[pkIdx] == null) {
                 res.startDataRequest(fm);
                 vals[pkIdx] = join.getPrimaryKeyValue(res, join.getColumns(),
-                    fk, joins);
+                    fk, store, joins);
                 res.endDataRequest();
                 if (vals[pkIdx] == null)
                     return null;

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java Fri Nov  3 15:15:08 2006
@@ -88,10 +88,10 @@
         return _join.getFieldIndex();
     }
 
-    public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk,
-        Joins joins)
+    public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk, 
+        JDBCStore store, Joins joins)
         throws SQLException {
-        return _join.getPrimaryKeyValue(res, cols, fk, joins);
+        return _join.getPrimaryKeyValue(res, cols, fk, store, joins);
     }
 
     public Column[] getColumns() {

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Joinable.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Joinable.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Joinable.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Joinable.java Fri Nov  3 15:15:08 2006
@@ -52,7 +52,7 @@
      * {@link ForeignKey#getColumn}.
      */
     public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk,
-        Joins joins)
+        JDBCStore store, Joins joins)
         throws SQLException;
 
     /**

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingRepository.java Fri Nov  3 15:15:08 2006
@@ -303,8 +303,8 @@
         // define superclass fields after mapping class, so we can tell whether
         // the class is mapped and needs to redefine abstract superclass fields
         getStrategyInstaller().installStrategy(mapping);
-        mapping.defineSuperclassFields(mapping.
-            getJoinablePCSuperclassMapping() == null);
+        mapping.defineSuperclassFields(mapping.getJoinablePCSuperclassMapping()
+            == null);
 
         // resolve everything that doesn't involve relations to allow relation
         // mappings to use the others as joinables

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java Fri Nov  3 15:15:08 2006
@@ -949,6 +949,10 @@
             throw new InternalException();
         }
 
+        public Object getPCPrimaryKey(Object oid, int field) {
+            throw new InternalException();
+        }
+
         public StateManager replaceStateManager(StateManager sm) {
             throw new InternalException();
         }

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerFieldStrategy.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerFieldStrategy.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerFieldStrategy.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerFieldStrategy.java Fri Nov  3 15:15:08 2006
@@ -287,7 +287,7 @@
     }
 
     public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk,
-        Joins joins)
+        JDBCStore store, Joins joins)
         throws SQLException {
         Column col;
         Object val = null;

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/IdentityJoinable.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/IdentityJoinable.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/IdentityJoinable.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/IdentityJoinable.java Fri Nov  3 15:15:08 2006
@@ -50,7 +50,7 @@
     }
 
     public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk,
-        Joins joins)
+        JDBCStore store, Joins joins)
         throws SQLException {
         Column col = cols[0];
         if (fk != null)

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/PrimitiveFieldStrategy.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/PrimitiveFieldStrategy.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/PrimitiveFieldStrategy.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/PrimitiveFieldStrategy.java Fri Nov  3 15:15:08 2006
@@ -287,12 +287,13 @@
     }
 
     public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk,
-        Joins joins)
+        JDBCStore store, Joins joins)
         throws SQLException {
         Column col = cols[0];
         if (fk != null)
             col = fk.getColumn(col);
-        return res.getObject(col, null, joins);
+        return JavaTypes.convert(res.getObject(col, null, joins),
+            field.getTypeCode());
     }
 
     public Column[] getColumns() {

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java Fri Nov  3 15:15:08 2006
@@ -24,12 +24,14 @@
 import org.apache.openjpa.jdbc.meta.ClassMapping;
 import org.apache.openjpa.jdbc.meta.Embeddable;
 import org.apache.openjpa.jdbc.meta.FieldMapping;
+import org.apache.openjpa.jdbc.meta.Joinable;
 import org.apache.openjpa.jdbc.meta.MappingInfo;
 import org.apache.openjpa.jdbc.meta.ValueMapping;
 import org.apache.openjpa.jdbc.meta.ValueMappingInfo;
 import org.apache.openjpa.jdbc.schema.Column;
 import org.apache.openjpa.jdbc.schema.ColumnIO;
 import org.apache.openjpa.jdbc.schema.ForeignKey;
+import org.apache.openjpa.jdbc.schema.PrimaryKey;
 import org.apache.openjpa.jdbc.schema.Table;
 import org.apache.openjpa.jdbc.sql.DBDictionary;
 import org.apache.openjpa.jdbc.sql.Joins;
@@ -45,8 +47,12 @@
 import org.apache.openjpa.lib.util.Localizer;
 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.MetaDataException;
 import org.apache.openjpa.util.OpenJPAId;
+import org.apache.openjpa.util.UnsupportedException;
+import serp.util.Numbers;
 
 /**
  * Mapping for a single-valued relation to another entity.
@@ -56,7 +62,7 @@
  */
 public class RelationFieldStrategy
     extends AbstractFieldStrategy
-    implements Embeddable {
+    implements Joinable, Embeddable {
 
     private static final Localizer _loc = Localizer.forPackage
         (RelationFieldStrategy.class);
@@ -146,8 +152,19 @@
                 adapt);
 
         field.setUseClassCriteria(criteria);
-        field.mapConstraints(field.getName(), adapt);
         field.mapPrimaryKey(adapt);
+        PrimaryKey pk = field.getTable().getPrimaryKey();
+        if (field.isPrimaryKey()) {
+            Column[] cols = field.getColumns();
+            if (pk != null && (adapt || pk.isLogical()))
+                for (int i = 0; i < cols.length; i++)
+                    pk.addColumn(cols[i]);
+            for (int i = 0; i < cols.length; i++)
+                field.getDefiningMapping().setJoinable(cols[i], this);
+        }
+
+        // map constraints after pk so we don't re-index / re-unique pk col
+        field.mapConstraints(field.getName(), adapt);
     }
 
     /**
@@ -690,6 +707,96 @@
                 field.getSelectSubclasses(), false, false);
         return joins.joinRelation(field.getName(), field.getForeignKey(clss[0]),
             clss[0], field.getSelectSubclasses(), false, false);
+    }
+
+    ///////////////////////////
+    // Joinable implementation
+    ///////////////////////////
+
+    public int getFieldIndex() {
+        return field.getIndex();
+    }
+
+    public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk,
+        JDBCStore store, Joins joins)
+        throws SQLException {
+        ClassMapping relmapping = field.getTypeMapping();
+        if (relmapping.getIdentityType() == ClassMapping.ID_DATASTORE) {
+            Column col = cols[0];
+            if (fk != null)
+                col = fk.getColumn(col);   
+            long id = res.getLong(col, joins);
+            if (field.getObjectIdFieldTypeCode() == JavaTypes.LONG)
+                return Numbers.valueOf(id);
+            return store.newDataStoreId(id, relmapping, field.getPolymorphic() 
+                != ValueMapping.POLY_FALSE);
+        }
+
+        if (relmapping.isOpenJPAIdentity())
+            return ((Joinable) relmapping.getPrimaryKeyFieldMappings()[0].
+                getStrategy()).getPrimaryKeyValue(res, cols, fk, store, joins);
+
+        if (cols == getColumns() && fk == null)
+            fk = field.getForeignKey();
+        else
+            fk = createTranslatingForeignKey(relmapping, cols, fk); 
+        return relmapping.getObjectId(store, res, fk,
+            field.getPolymorphic() != ValueMapping.POLY_FALSE, joins);
+    }
+
+    /**
+     * Create a faux foreign key that translates between the columns to pull
+     * the data from and our related type's primary key columns.
+     */
+    private ForeignKey createTranslatingForeignKey(ClassMapping relmapping,
+        Column[] gcols, ForeignKey gfk) {
+        ForeignKey fk = field.getForeignKey(); 
+        Column[] cols = fk.getColumns();
+
+        ForeignKey tfk = null;
+        Column tcol;
+        for (int i = 0; i < gcols.length; i++) {
+            tcol = gcols[i];
+            if (gfk != null)
+                tcol = gfk.getColumn(tcol);
+            if (tfk == null)
+                tfk = new ForeignKey(null, tcol.getTable());
+            tfk.join(tcol, fk.getPrimaryKeyColumn(cols[i]));
+        }
+        return tfk;
+    }
+
+    public Object getJoinValue(Object fieldVal, Column col, JDBCStore store) {
+        Object o = field.getForeignKey().getConstant(col);
+        if (o != null)
+            return o;
+        col = field.getForeignKey().getPrimaryKeyColumn(col);
+        if (col == null)
+            throw new InternalException();
+
+        ClassMapping relmapping = field.getTypeMapping();
+        Joinable j = field.getTypeMapping().assertJoinable(col);
+        if (ImplHelper.isManageable(fieldVal))
+            fieldVal = store.getContext().getObjectId(fieldVal);
+        if (fieldVal instanceof OpenJPAId)
+            fieldVal = ((OpenJPAId) fieldVal).getIdObject();
+        else if (relmapping.getObjectIdType() != null
+            && relmapping.getObjectIdType().isInstance(fieldVal)) {
+            Object[] pks = ApplicationIds.toPKValues(fieldVal, relmapping);
+            fieldVal = pks[relmapping.getField(j.getFieldIndex()).
+                getPrimaryKeyIndex()];
+        }
+        return j.getJoinValue(fieldVal, col, store);
+    }
+
+    public Object getJoinValue(OpenJPAStateManager sm, Column col,
+        JDBCStore store) {
+        return getJoinValue(sm.fetch(field.getIndex()), col, store);
+    }
+
+    public void setAutoAssignedValue(OpenJPAStateManager sm, JDBCStore store,
+        Column col, Object autoInc) {
+        throw new UnsupportedException();
     }
 
     /////////////////////////////

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StringFieldStrategy.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StringFieldStrategy.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StringFieldStrategy.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StringFieldStrategy.java Fri Nov  3 15:15:08 2006
@@ -201,7 +201,7 @@
     }
 
     public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk,
-        Joins joins)
+        JDBCStore store, Joins joins)
         throws SQLException {
         Column col = cols[0];
         if (fk != null)

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/schemas-doctype.rsrc
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/schemas-doctype.rsrc?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/schemas-doctype.rsrc (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/schema/schemas-doctype.rsrc Fri Nov  3 15:15:08 2006
@@ -2,7 +2,7 @@
 	<!ELEMENT schemas (schema)*>
 	<!ELEMENT schema (table|sequence)*>
 	<!ATTLIST schema name CDATA #IMPLIED>
-	<!ELEMENT table (column|index|pk|fk)+>
+	<!ELEMENT table (column|index|pk|fk|unique)+>
 	<!ATTLIST table name CDATA #REQUIRED>
 	<!ELEMENT column EMPTY>
 	<!ATTLIST column name CDATA #REQUIRED> 

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java Fri Nov  3 15:15:08 2006
@@ -312,7 +312,6 @@
 
         // collect info on id type
         String className = getClassName();
-
         String packageName = Strings.getPackageName(oidClass);
         String packageDec = "";
         if (packageName.length() > 0)
@@ -502,13 +501,12 @@
 
         pkgs.add("java.io");
         pkgs.add("java.util");
+        Class type;
         for (int i = 0; i < _fields.length; i++) {
-            if (_fields[i].getDeclaredType() != byte[].class
-                && _fields[i].getDeclaredType() != char[].class
-                && !_fields[i].getDeclaredType().getName().
-                startsWith("java.sql.")) {
-                pkgs.add(Strings.getPackageName
-                    (_fields[i].getDeclaredType()));
+            type = _fields[i].getObjectIdFieldType();
+            if (type != byte[].class && type != char[].class
+                && !type.getName().startsWith("java.sql.")) {
+                pkgs.add(Strings.getPackageName(type));
             }
         }
         return pkgs;
@@ -532,13 +530,14 @@
      * Return the type name to declare the given field as.
      */
     private String getTypeName(FieldMetaData fmd) {
-        if (fmd.getDeclaredType() == byte[].class)
+        Class type = fmd.getObjectIdFieldType();
+        if (type == byte[].class)
             return "byte[]";
-        if (fmd.getDeclaredType() == char[].class)
+        if (type == char[].class)
             return "char[]";
-        if (fmd.getDeclaredType().getName().startsWith("java.sql."))
-            return fmd.getDeclaredType().getName();
-        return Strings.getClassName(fmd.getDeclaredType());
+        if (type.getName().startsWith("java.sql."))
+            return type.getName();
+        return Strings.getClassName(type);
     }
 
     /**
@@ -626,6 +625,16 @@
         code.openParen(true).append("String str").closeParen();
         code.openBrace(2).endl();
 
+        // if we have any Object-type fields, die immediately 
+        for (int i = 0; i < _fields.length; i++) {
+            if (_fields[i].getObjectIdFieldType() != Object.class)
+                continue;
+            code.tab(2).append("throw new UnsupportedOperationException").
+                parens().append(";").endl();
+            code.closeBrace(2); 
+            return code.toString();
+        } 
+
         if (toke != null) {
             code.tab(2).append(toke).append(" toke = ");
             if (hasSuperclass) {
@@ -677,7 +686,7 @@
             parse.append("this.");
         parse.append(field.getName()).append(" = ");
 
-        Class type = field.getDeclaredType();
+        Class type = field.getObjectIdFieldType();
         if (type == Date.class) {
             parse.append("new Date").openParen(true).
                 append("Long.parseLong").openParen(true).
@@ -788,6 +797,7 @@
         }
 
         String name;
+        Class type;
         for (int i = 0; i < _fields.length; i++) {
             if (i == 0) {
                 code.endl().tab(2).append(className).append(" other = ").
@@ -802,14 +812,15 @@
                 code.endl().tab(3).append("&& ");
 
             name = _fields[i].getName();
-            if (_fields[i].getDeclaredType().isPrimitive()) {
+            type = _fields[i].getObjectIdFieldType();
+            if (type.isPrimitive()) {
                 code.openParen(false).append(name).append(" == ").
                     append("other.").append(name).closeParen();
-            } else if (_fields[i].getDeclaredType() == byte[].class) {
+            } else if (type == byte[].class) {
                 code.openParen(false).append("equals").openParen(true).
                     append(name).append(", ").append("other.").
                     append(name).closeParen().closeParen();
-            } else if (_fields[i].getDeclaredType() == char[].class) {
+            } else if (type == char[].class) {
                 // ((name == null && other.name == null)
                 //	|| (name != null && String.valueOf (name).
                 //	equals (String.valueOf (other.name))))
@@ -908,18 +919,19 @@
         String name = field.getName();
         if ("rs".equals(name))
             name = "this." + name;
-        if (field.getDeclaredType().isPrimitive()) {
-            if (field.getDeclaredType() == boolean.class) {
+        Class type = field.getObjectIdFieldType();
+        if (type.isPrimitive()) {
+            if (type == boolean.class) {
                 // ((name) ? 1 : 0)
                 code.append("(").openParen(false).append(name).closeParen().
                     append(" ? 1 : 0").append(")");
-            } else if (field.getDeclaredType() == long.class) {
+            } else if (type == long.class) {
                 // (int) (name ^ (name >>> 32))
                 code.openParen(false).append("int").closeParen().
                     append(" ").openParen(false).append(name).
                     append(" ^ ").openParen(false).append(name).
                     append(" >>> 32").closeParen().closeParen();
-            } else if (field.getDeclaredType() == double.class) {
+            } else if (type == double.class) {
                 // (int) (Double.doubleToLongBits (name)
                 //     ^ (Double.doubleToLongBits (name) >>> 32))
                 code.openParen(false).append("int").closeParen().
@@ -930,22 +942,22 @@
                     append("Double.doubleToLongBits").openParen(true).
                     append(name).closeParen().append(" >>> 32").
                     closeParen().closeParen();
-            } else if (field.getDeclaredType() == float.class) {
+            } else if (type == float.class) {
                 // Float.floatToIntBits (name)
                 code.append("Float.floatToIntBits").openParen(true).
                     append(name).closeParen();
-            } else if (field.getDeclaredType() == int.class)
+            } else if (type == int.class)
                 code.append(name);
             else {
                 // (int) name
                 code.openParen(false).append("int").closeParen().
                     append(" ").append(name);
             }
-        } else if (field.getDeclaredType() == byte[].class) {
+        } else if (type == byte[].class) {
             // hashCode (name);
             code.append("hashCode").openParen(true).append(name).
                 closeParen();
-        } else if (field.getDeclaredType() == char[].class) {
+        } else if (type == char[].class) {
             // ((name == null) ? 0 : String.valueOf (name).hashCode ())
             code.append("(").openParen(false).append(name).
                 append(" == null").closeParen().append(" ? 0 : ").
@@ -974,6 +986,7 @@
             openBrace(2).endl();
 
         String name;
+        Class type;
         String appendDelimiter = "+ \"" + _token + "\" + ";
         for (int i = 0; i < _fields.length; i++) {
             // if this is not the first field, add a +
@@ -990,17 +1003,18 @@
                 code.endl().tab(3).append(appendDelimiter);
 
             name = _fields[i].getName();
-            if (_fields[i].getDeclaredType() == String.class)
+            type = _fields[i].getObjectIdFieldType();
+            if (type == String.class)
                 code.append(name);
-            else if (_fields[i].getDeclaredType() == byte[].class)
+            else if (type == byte[].class)
                 code.append("toString").openParen(true).
                     append(name).closeParen();
-            else if (_fields[i].getDeclaredType() == char[].class)
+            else if (type == char[].class)
                 code.openParen(true).openParen(true).append(name).
                     append(" == null").closeParen().append(" ? \"null\"").
                     append(": String.valueOf").openParen(true).
                     append(name).closeParen().closeParen();
-            else if (_fields[i].getDeclaredType() == Date.class)
+            else if (type == Date.class)
                 code.openParen(true).openParen(true).append(name).
                     append(" == null").closeParen().append(" ? \"null\"").
                     endl().tab(4).append(": String.valueOf").
@@ -1448,7 +1462,8 @@
     public static interface ObjectIdLoader
 	{
 		/**
-		 * Turn on the loading of all identity classes, even if they don't exist.
+		 * Turn on the loading of all identity classes, even if they don't 
+         * exist.
 	 	 */
 		public void setLoadObjectIds ();
 	}

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java Fri Nov  3 15:15:08 2006
@@ -31,6 +31,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -59,7 +60,15 @@
 import org.apache.openjpa.meta.ValueStrategies;
 import org.apache.openjpa.util.GeneralException;
 import org.apache.openjpa.util.InternalException;
+import org.apache.openjpa.util.ByteId;
+import org.apache.openjpa.util.CharId;
+import org.apache.openjpa.util.DateId;
+import org.apache.openjpa.util.Id;
+import org.apache.openjpa.util.IntId;
+import org.apache.openjpa.util.LongId;
 import org.apache.openjpa.util.ObjectId;
+import org.apache.openjpa.util.ShortId;
+import org.apache.openjpa.util.StringId;
 import org.apache.openjpa.util.OpenJPAException;
 import org.apache.openjpa.util.UserException;
 import serp.bytecode.BCClass;
@@ -131,7 +140,6 @@
     private final ClassMetaData _meta;
     private final Log _log;
     private Collection _oids = null;
-
     private boolean _defCons = true;
     private boolean _fail = false;
     private File _dir = null;
@@ -1285,14 +1293,14 @@
             code.constant().setNull(); // return null;
         else {
             // return <versionField>;
-            Class wrapper = unwrapVersionField(versionField);
-            if (wrapper != null) {
+            Class wrapper = toPrimitiveWrapper(versionField);
+            if (wrapper != versionField.getDeclaredType()) {
                 code.anew().setType(wrapper);
                 code.dup();
             }
             loadManagedInstance(code, false);
             addGetManagedValueCode(code, versionField);
-            if (wrapper != null)
+            if (wrapper != versionField.getDeclaredType())
                 code.invokespecial().setMethod(wrapper, "<init>", void.class,
                     new Class[]{ versionField.getDeclaredType() });
         }
@@ -1313,20 +1321,26 @@
      * Return the version field type as a primitive wrapper, or null if
      * the version field is not primitive.
      */
-    private Class unwrapVersionField(FieldMetaData fmd) {
+    private Class toPrimitiveWrapper(FieldMetaData fmd) {
         switch (fmd.getDeclaredTypeCode()) {
+            case JavaTypes.BOOLEAN:
+                return Boolean.class;
             case JavaTypes.BYTE:
                 return Byte.class;
             case JavaTypes.CHAR:
                 return Character.class;
+            case JavaTypes.DOUBLE:
+                return Double.class;
+            case JavaTypes.FLOAT:
+                return Float.class;
             case JavaTypes.INT:
                 return Integer.class;
-            case JavaTypes.SHORT:
-                return Short.class;
             case JavaTypes.LONG:
                 return Long.class;
+            case JavaTypes.SHORT:
+                return Short.class;
         }
-        return null;
+        return fmd.getDeclaredType();
     }
 
     /**
@@ -1495,7 +1509,7 @@
         else
             code.aload().setParam(0);
 
-        if (!_meta.isOpenJPAIdentity() && _meta.isObjectIdTypeShared()) {
+        if (_meta.isObjectIdTypeShared()) {
             // oid = ((ObjectId) id).getId ();
             code.checkcast().setType(ObjectId.class);
             code.invokevirtual().setMethod(ObjectId.class, "getId",
@@ -1509,9 +1523,12 @@
         code.astore().setLocal(id);
 
         // int inherited = pcInheritedFieldCount;
-        code.getstatic().setField(INHERIT, int.class);
-        int inherited = code.getNextLocalsIndex();
-        code.istore().setLocal(inherited);
+        int inherited = 0;
+        if (fieldManager) {
+            code.getstatic().setField(INHERIT, int.class);
+            inherited = code.getNextLocalsIndex();
+            code.istore().setLocal(inherited);
+        }
 
         // id.<field> = fs.fetch<type>Field (<index>); or...
         // id.<field> = pc.<field>;
@@ -1522,8 +1539,9 @@
             if (!fmds[i].isPrimaryKey())
                 continue;
 
-            type = fmds[i].getDeclaredType();
             name = fmds[i].getName();
+            type = fmds[i].getObjectIdFieldType();
+
             code.aload().setLocal(id);
             if (fieldManager) {
                 code.aload().setParam(0);
@@ -1542,11 +1560,14 @@
             } else {
                 loadManagedInstance(code, false);
                 addGetManagedValueCode(code, fmds[i]);
+
+                // get id/pk from pc instance
+                if (fmds[i].getDeclaredTypeCode() == JavaTypes.PC)
+                    addExtractObjectIdFieldValueCode(code, fmds[i]);
             }
 
             if (_meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
-                code.putfield().setField(findDeclaredField(oidType,
-                    name));
+                code.putfield().setField(findDeclaredField(oidType, name));
             else
                 code.invokevirtual().setMethod(findDeclaredMethod
                     (oidType, "set" + StringUtils.capitalize(name),
@@ -1559,6 +1580,168 @@
     }
 
     /**
+     * Add code to extract the id of the given primary key relation field for
+     * setting into an objectid instance.
+     */
+    private void addExtractObjectIdFieldValueCode(Code code, FieldMetaData pk) {
+        // if (val != null) 
+        //  val = ((PersistenceCapable) val).pcFetchObjectId();
+        int pc = code.getNextLocalsIndex();
+        code.astore().setLocal(pc);
+        code.aload().setLocal(pc);
+        JumpInstruction ifnull1 = code.ifnull();
+        code.aload().setLocal(pc);
+        code.checkcast().setType(PersistenceCapable.class); 
+        code.invokeinterface().setMethod(PersistenceCapable.class,
+            PRE + "FetchObjectId", Object.class, null);
+        int oid = code.getNextLocalsIndex();
+        code.astore().setLocal(oid);
+        code.aload().setLocal(oid);
+        JumpInstruction ifnull2 = code.ifnull(); 
+
+        // for datastore / single-field identity:
+        // if (val != null)
+        //   val = ((OpenJPAId) val).getId();
+        ClassMetaData pkmeta = pk.getDeclaredTypeMetaData();
+        int pkcode = pk.getObjectIdFieldTypeCode();
+        Class pktype = pk.getObjectIdFieldType();
+        if (pkmeta.getIdentityType() == ClassMetaData.ID_DATASTORE 
+            && pkcode == JavaTypes.LONG) {
+            code.aload().setLocal(oid);
+            code.checkcast().setType(Id.class);
+            code.invokevirtual().setMethod(Id.class, "getId", 
+                long.class, null);
+        } else if (pkmeta.getIdentityType() == ClassMetaData.ID_DATASTORE) {
+            code.aload().setLocal(oid);
+        } else if (pkmeta.isOpenJPAIdentity()) {
+            switch (pkcode) {
+                case JavaTypes.BYTE_OBJ:
+                    code.anew().setType(Byte.class);
+                    code.dup();
+                    // no break
+                case JavaTypes.BYTE:
+                    code.aload().setLocal(oid);
+                    code.checkcast().setType(ByteId.class);
+                    code.invokevirtual().setMethod(ByteId.class, "getId",
+                        byte.class, null);
+                    if (pkcode == JavaTypes.BYTE_OBJ)
+                        code.invokespecial().setMethod(Byte.class, "<init>",
+                            void.class, new Class[] {byte.class});
+                    break;
+                case JavaTypes.CHAR_OBJ:
+                    code.anew().setType(Character.class);
+                    code.dup();
+                    // no break
+                case JavaTypes.CHAR:
+                    code.aload().setLocal(oid);
+                    code.checkcast().setType(CharId.class);
+                    code.invokevirtual().setMethod(CharId.class, "getId",
+                        char.class, null);
+                    if (pkcode == JavaTypes.CHAR_OBJ)
+                        code.invokespecial().setMethod(Character.class, 
+                            "<init>", void.class, new Class[] {char.class});
+                    break;
+                case JavaTypes.INT_OBJ:
+                    code.anew().setType(Integer.class);
+                    code.dup();
+                    // no break
+                case JavaTypes.INT:
+                    code.aload().setLocal(oid);
+                    code.checkcast().setType(IntId.class);
+                    code.invokevirtual().setMethod(IntId.class, "getId",
+                        int.class, null);
+                    if (pkcode == JavaTypes.INT_OBJ)
+                        code.invokespecial().setMethod(Integer.class, "<init>",
+                            void.class, new Class[] {int.class});
+                    break;
+                case JavaTypes.LONG_OBJ:
+                    code.anew().setType(Long.class);
+                    code.dup();
+                    // no break
+                case JavaTypes.LONG:
+                    code.aload().setLocal(oid);
+                    code.checkcast().setType(LongId.class);
+                    code.invokevirtual().setMethod(LongId.class, "getId",
+                        long.class, null);
+                    if (pkcode == JavaTypes.LONG_OBJ)
+                        code.invokespecial().setMethod(Long.class, "<init>",
+                            void.class, new Class[] {long.class});
+                    break;
+                case JavaTypes.SHORT_OBJ:
+                    code.anew().setType(Short.class);
+                    code.dup();
+                    // no break
+                case JavaTypes.SHORT:
+                    code.aload().setLocal(oid);
+                    code.checkcast().setType(ShortId.class);
+                    code.invokevirtual().setMethod(ShortId.class, "getId",
+                        short.class, null);
+                    if (pkcode == JavaTypes.SHORT_OBJ)
+                        code.invokespecial().setMethod(Short.class, "<init>", 
+                            void.class, new Class[]{short.class});
+                    break;
+                case JavaTypes.DATE:
+                    code.aload().setLocal(oid);
+                    code.checkcast().setType(DateId.class);
+                    code.invokevirtual().setMethod(DateId.class, "getId",
+                        Date.class, null);
+                    break;
+                case JavaTypes.STRING:
+                    code.aload().setLocal(oid);
+                    code.checkcast().setType(StringId.class);
+                    code.invokevirtual().setMethod(StringId.class, "getId",
+                        String.class, null);
+                    break;
+                default:
+                    code.aload().setLocal(oid);
+                    code.checkcast().setType(ObjectId.class);
+                    code.invokevirtual().setMethod(ObjectId.class, "getId",
+                        Object.class, null);
+            }
+        } else if (pkmeta.getObjectIdType() != null) {
+            code.aload().setLocal(oid);
+            code.checkcast().setType(pktype);
+        } else
+            code.aload().setLocal(oid);
+        JumpInstruction go2 = code.go2();
+
+        // if (val == null)
+        //   val = <default>;
+        Instruction def;
+        switch (pkcode) {
+            case JavaTypes.BOOLEAN:
+                def = code.constant().setValue(false);
+                break;
+            case JavaTypes.BYTE:
+                def = code.constant().setValue((byte) 0);
+                break;
+            case JavaTypes.CHAR:
+                def = code.constant().setValue((char) 0);
+                break;
+            case JavaTypes.DOUBLE:
+                def = code.constant().setValue(0D);
+                break;
+            case JavaTypes.FLOAT:
+                def = code.constant().setValue(0F);
+                break;
+            case JavaTypes.INT:
+                def = code.constant().setValue(0);
+                break;
+            case JavaTypes.LONG:
+                def = code.constant().setValue(0L);
+                break;
+            case JavaTypes.SHORT:
+                def = code.constant().setValue((short) 0);
+                break;
+            default:
+                def = code.constant().setNull();
+        }
+        ifnull1.setTarget(def);
+        ifnull2.setTarget(def);
+        go2.setTarget(code.nop());
+    }
+
+    /**
      * Adds the <code>pcCopyKeyFieldsFromObjectId</code> methods
      * to classes using application identity.
      */
@@ -1566,8 +1749,8 @@
         throws NoSuchMethodException {
         // public void pcCopyKeyFieldsFromObjectId (ObjectIdFieldConsumer fc,
         //	Object oid)
-        String[] args = (fieldManager) ?
-            new String[]{ OIDFCTYPE.getName(), Object.class.getName() }
+        String[] args = (fieldManager) 
+            ?  new String[]{ OIDFCTYPE.getName(), Object.class.getName() }
             : new String[]{ Object.class.getName() };
         BCMethod method = _pc.declareMethod(PRE + "CopyKeyFieldsFromObjectId",
             void.class.getName(), args);
@@ -1601,14 +1784,6 @@
         code.checkcast().setType(oidType);
         code.astore().setLocal(id);
 
-        // int inherited = pcInheritedFieldCount;
-        int inherited = 0;
-        if (fieldManager) {
-            code.getstatic().setField(INHERIT, int.class);
-            inherited = code.getNextLocalsIndex();
-            code.istore().setLocal(inherited);
-        }
-
         // fs.store<type>Field (<index>, id.<field>); or...
         // this.<field> = id.<field>
         // or for single field identity: id.getId ()
@@ -1621,41 +1796,56 @@
                 continue;
 
             name = fmds[i].getName();
-            type = fmds[i].getDeclaredType();
-            unwrapped = unwrapSingleFieldIdentity(fmds[i]);
-
-            if (fieldManager) {
-                code.aload().setParam(0);
+            type = fmds[i].getObjectIdFieldType();
+            if (!fieldManager 
+                && fmds[i].getDeclaredTypeCode() == JavaTypes.PC) {
+                // sm.getPCPrimaryKey(oid, i + pcInheritedFieldCount); 
+                loadManagedInstance(code, false);
+                code.dup(); // leave orig on stack to set value into
+                code.getfield().setField(SM, SMTYPE);
+                code.aload().setLocal(id);
                 code.constant().setValue(i);
-                code.iload().setLocal(inherited);
+                code.getstatic().setField(INHERIT, int.class);
                 code.iadd();
-            } else
-                loadManagedInstance(code, false);
-
-            if (unwrapped != type) {
-                code.anew().setType(type);
-                code.dup();
-            }
-            code.aload().setLocal(id);
-            if (_meta.isOpenJPAIdentity()) {
-                if (oidType == ObjectId.class) {
-                    code.invokevirtual().setMethod(oidType, "getId",
-                        Object.class, null);
-                    if (!fieldManager && fmds[i].getDeclaredType()
-                        != Object.class)
-                        code.checkcast().setType(fmds[i].getDeclaredType());
-                } else {
-                    code.invokevirtual().setMethod(oidType, "getId",
-                        unwrapped, null);
-                    if (unwrapped != type)
-                        code.invokespecial().setMethod(type, "<init>",
-                            void.class, new Class[]{ unwrapped });
+                code.invokeinterface().setMethod(StateManager.class, 
+                    "getPCPrimaryKey", Object.class, 
+                    new Class[] { Object.class, int.class });
+                code.checkcast().setType(fmds[i].getDeclaredType());
+            } else { 
+                unwrapped = (fmds[i].getDeclaredTypeCode() == JavaTypes.PC) 
+                    ? type : unwrapSingleFieldIdentity(fmds[i]);
+                if (fieldManager) {
+                    code.aload().setParam(0);
+                    code.constant().setValue(i);
+                    code.getstatic().setField(INHERIT, int.class);
+                    code.iadd();
+                } else
+                    loadManagedInstance(code, false);
+
+                if (unwrapped != type) {
+                    code.anew().setType(type);
+                    code.dup();
                 }
-            } else if (_meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
-                code.getfield().setField(findDeclaredField(oidType, name));
-            else // property
-                code.invokevirtual().setMethod(findDeclaredGetterMethod
-                    (oidType, StringUtils.capitalize(name)));
+                code.aload().setLocal(id);
+                if (_meta.isOpenJPAIdentity()) {
+                    if (oidType == ObjectId.class) {
+                        code.invokevirtual().setMethod(oidType, "getId",
+                            Object.class, null);
+                        if (!fieldManager && type != Object.class)
+                            code.checkcast().setType(fmds[i].getDeclaredType());
+                    } else {
+                        code.invokevirtual().setMethod(oidType, "getId", 
+                            unwrapped, null);
+                        if (unwrapped != type)
+                            code.invokespecial().setMethod(type, "<init>",
+                                void.class, new Class[]{ unwrapped });
+                    }
+                } else if (_meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
+                    code.getfield().setField(findDeclaredField(oidType, name));
+                else // property
+                    code.invokevirtual().setMethod(findDeclaredGetterMethod
+                        (oidType, StringUtils.capitalize(name)));
+            }
 
             if (fieldManager)
                 code.invokeinterface().setMethod(getFieldConsumerMethod(type));
@@ -1793,10 +1983,12 @@
             loadManagedInstance(code, false);
             FieldMetaData pk = _meta.getPrimaryKeyFields()[0];
             addGetManagedValueCode(code, pk);
+            if (pk.getDeclaredTypeCode() == JavaTypes.PC)
+                addExtractObjectIdFieldValueCode(code, pk);
             if (_meta.getObjectIdType() == ObjectId.class)
                 args = new Class[]{ Class.class, Object.class };
             else
-                args = new Class[]{ Class.class, pk.getDeclaredType() };
+                args = new Class[]{ Class.class, pk.getObjectIdFieldType() };
         }
 
         code.invokespecial().setMethod(oidType, "<init>", void.class, args);

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/StateManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/StateManager.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/StateManager.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/StateManager.java Fri Nov  3 15:15:08 2006
@@ -34,6 +34,13 @@
     public Object getGenericContext();
 
     /**
+     * Return the persistence-capable primary key object by extracting the 
+     * identity value of the related instance stored in the given field from 
+     * the given object id.
+     */
+    public Object getPCPrimaryKey(Object oid, int field);
+
+    /**
      * Change internal flags.
      */
     public byte replaceFlags();

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java Fri Nov  3 15:15:08 2006
@@ -2761,7 +2761,7 @@
             // refresh all
             if (load != null) {
                 Collection failed = _store.loadAll(load, null,
-                    _store.FORCE_LOAD_REFRESH, _fc, null);
+                    StoreManager.FORCE_LOAD_REFRESH, _fc, null);
                 if (failed != null && !failed.isEmpty())
                     exceps = add(exceps, newObjectNotFoundException(failed));
 

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java Fri Nov  3 15:15:08 2006
@@ -323,6 +323,10 @@
         return PersistenceCapable.MEDIATE_WRITE;
     }
 
+    public Object getPCPrimaryKey(Object oid, int field) {
+        throw new UnsupportedOperationException();
+    }
+
     public StateManager replaceStateManager(StateManager sm) {
         return sm;
     }

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java Fri Nov  3 15:15:08 2006
@@ -399,6 +399,10 @@
         return _ctx;
     }
 
+    public Object getPCPrimaryKey(Object oid, int field) {
+        throw new UnsupportedOperationException();
+    }
+
     public byte replaceFlags() {
         throw new UnsupportedOperationException();
     }

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java Fri Nov  3 15:15:08 2006
@@ -66,6 +66,10 @@
         return (_owner == null) ? null : _owner.getGenericContext();
     }
 
+    public Object getPCPrimaryKey(Object oid, int field) {
+        throw new UnsupportedOperationException();
+    }
+
     public byte replaceFlags() {
         throw new UnsupportedOperationException();
     }

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java Fri Nov  3 15:15:08 2006
@@ -215,9 +215,9 @@
         }
     }
 
-    ///////////////////////////////////
+    //////////////////////////////////////
     // OpenJPAStateManager implementation
-    ///////////////////////////////////
+    //////////////////////////////////////
 
     public void initialize(Class cls, PCState state) {
         // check to see if our current object id instance is the
@@ -1302,6 +1302,22 @@
         } catch (RuntimeException re) {
             throw translate(re);
         }
+    }
+
+    public Object getPCPrimaryKey(Object oid, int field) {
+        FieldMetaData fmd = _meta.getField(field);
+        Object pk = ApplicationIds.get(oid, fmd);
+        if (pk == null)
+            return null;
+
+        ClassMetaData relmeta = fmd.getDeclaredTypeMetaData();
+        if (relmeta.getIdentityType() == ClassMetaData.ID_DATASTORE
+            && fmd.getObjectIdFieldTypeCode() == JavaTypes.LONG)
+            pk = _broker.getStoreManager().newDataStoreId(pk, relmeta);
+        else if (relmeta.getIdentityType() == ClassMetaData.ID_APPLICATION 
+            && fmd.getObjectIdFieldType() != relmeta.getObjectIdType())
+            pk = ApplicationIds.fromPKValues(new Object[] { pk }, relmeta);
+        return _broker.find(pk, false, null);
     }
 
     public byte replaceFlags() {

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractMetaDataDefaults.java Fri Nov  3 15:15:08 2006
@@ -45,6 +45,7 @@
     private boolean _interface = true;
     private boolean _pcRegistry = true;
     private int _callback = CALLBACK_RETHROW;
+    private boolean _unwrapped = false;
 
     /**
      * Whether to attempt to use the information from registered classes
@@ -113,6 +114,22 @@
         return false;
     }
 
+    public boolean isDeclaredInterfacePersistent() {
+        return _interface;
+    }
+
+    public void setDeclaredInterfacePersistent(boolean pers) {
+        _interface = pers;
+    }
+
+    public boolean isDataStoreObjectIdFieldUnwrapped() {
+        return _unwrapped;
+    }
+
+    public void setDataStoreObjectIdFieldUnwrapped(boolean unwrapped) {
+        _unwrapped = unwrapped;
+    }
+
     public boolean getIgnoreNonPersistent() {
         return _ignore;
     }
@@ -281,14 +298,6 @@
      */
     protected abstract boolean isDefaultPersistent(ClassMetaData meta,
         Member member, String name);
-
-    public void setDeclaredInterfacePersistent(boolean pers) {
-        _interface = pers;
-    }
-
-    public boolean isDeclaredInterfacePersistent() {
-        return _interface;
-    }
 
     public Member getBackingMember(FieldMetaData fmd) {
         if (fmd == null)

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java Fri Nov  3 15:15:08 2006
@@ -428,7 +428,7 @@
         FieldMetaData[] pks = getPrimaryKeyFields();
         if (pks.length != 1)
             return null;
-        switch (pks[0].getDeclaredTypeCode()) {
+        switch (pks[0].getObjectIdFieldTypeCode()) {
             case JavaTypes.BYTE:
             case JavaTypes.BYTE_OBJ:
                 _objectId = ByteId.class;
@@ -456,6 +456,7 @@
                 _objectId = DateId.class;
                 break;
             case JavaTypes.OID:
+            case JavaTypes.OBJECT:
                 _objectId = ObjectId.class;
                 break;
         }
@@ -1898,29 +1899,32 @@
             Method m;
             String cap;
             int type;
-            Class comp;
+            Class c;
+            ClassMetaData idmeta;
             int access = meta.getAccessType();
             for (int i = 0; i < fmds.length; i++) {
                 switch (fmds[i].getDeclaredTypeCode()) {
                     case JavaTypes.ARRAY:
-                        comp = fmds[i].getDeclaredType().getComponentType();
-                        if (comp == byte.class || comp == Byte.class
-                            || comp == char.class || comp == Character.class)
+                        c = fmds[i].getDeclaredType().getComponentType();
+                        if (c == byte.class || c == Byte.class
+                            || c == char.class || c == Character.class) {
+                            c = fmds[i].getDeclaredType();
                             break;
+                        }
                         // else no break
+                    case JavaTypes.PC_UNTYPED:
                     case JavaTypes.COLLECTION:
                     case JavaTypes.MAP:
-                    case JavaTypes.PC:
-                    case JavaTypes.PC_UNTYPED:
                     case JavaTypes.OID: // we're validating embedded fields
                         throw new MetaDataException(_loc.get("bad-pk-type",
                             fmds[i]));
+                    default:
+                        c = fmds[i].getObjectIdFieldType();
                 }
 
                 if (access == ACCESS_FIELD) {
                     f = findField(oid, fmds[i].getName(), runtime);
-                    if (f == null || !f.getType().isAssignableFrom(fmds[i].
-                        getDeclaredType()))
+                    if (f == null || !f.getType().isAssignableFrom(c))
                         throw new MetaDataException(_loc.get("invalid-id",
                             _type)).setFailedObject(fmds[i].getName());
                 } else if (access == ACCESS_PROPERTY) {
@@ -1931,8 +1935,7 @@
                     if (m == null && (type == JavaTypes.BOOLEAN
                         || type == JavaTypes.BOOLEAN_OBJ))
                         m = findMethod(oid, "is" + cap, null, runtime);
-                    if (m == null || !m.getReturnType().
-                        isAssignableFrom(fmds[i].getDeclaredType()))
+                    if (m == null || !m.getReturnType().isAssignableFrom(c))
                         throw new MetaDataException(_loc.get("invalid-id",
                             _type)).setFailedObject("get" + cap);
 

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java Fri Nov  3 15:15:08 2006
@@ -506,6 +506,48 @@
     }
 
     /**
+     * For a primary key field, return the type of the corresponding object id 
+     * class field.
+     */
+    public int getObjectIdFieldTypeCode() {
+        ClassMetaData relmeta = getDeclaredTypeMetaData();
+        if (relmeta == null)
+            return getDeclaredTypeCode();
+        if (relmeta.getIdentityType() == ClassMetaData.ID_DATASTORE) {
+            boolean unwrap = getRepository().getMetaDataFactory().getDefaults().
+                isDataStoreObjectIdFieldUnwrapped();
+            return (unwrap) ? JavaTypes.LONG : JavaTypes.OBJECT;
+        }
+        if (relmeta.isOpenJPAIdentity())
+            return relmeta.getPrimaryKeyFields()[0].getObjectIdFieldTypeCode();
+        return JavaTypes.OBJECT;
+    }
+
+    /**
+     * For a primary key field, return the type of the corresponding object id 
+     * class field.
+     */
+    public Class getObjectIdFieldType() {
+        ClassMetaData relmeta = getDeclaredTypeMetaData();
+        if (relmeta == null)
+            return getDeclaredType();
+        switch (relmeta.getIdentityType()) {
+            case ClassMetaData.ID_DATASTORE:
+                boolean unwrap = getRepository().getMetaDataFactory().
+                    getDefaults().isDataStoreObjectIdFieldUnwrapped();
+                return (unwrap) ? long.class : Object.class;
+            case ClassMetaData.ID_APPLICATION:
+                if (relmeta.isOpenJPAIdentity())
+                    return relmeta.getPrimaryKeyFields()[0].
+                        getObjectIdFieldType();
+                return (relmeta.getObjectIdType() == null) ? Object.class
+                    : relmeta.getObjectIdType();
+            default:
+                return Object.class;
+        } 
+    }
+
+    /**
      * Whether this field holds optimistic version information.
      */
     public boolean isVersion() {

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataDefaults.java Fri Nov  3 15:15:08 2006
@@ -49,18 +49,25 @@
      * event type. Defaults to false.
      */
     public boolean getCallbacksBeforeListeners(int type);
-    
-    /**
-     * Whether to ignore members which are not persistent by default
-     * during metadata population. Defaults to true.
-     */
-    public void setIgnoreNonPersistent(boolean ignore);
-
+   
     /**
      * Whether declared interfaces of a class are treated as persistent
      * types. Defaults to true.
      */
     public boolean isDeclaredInterfacePersistent();
+
+    /**
+     * Whether the field in the object id class corresponding to a 
+     * datastore id persistence-capable primary key field is the simple 
+     * datastore id value of the related instance.  Defaults to false.
+     */
+    public boolean isDataStoreObjectIdFieldUnwrapped();
+ 
+    /**
+     * Whether to ignore members which are not persistent by default
+     * during metadata population. Defaults to true.
+     */
+    public void setIgnoreNonPersistent(boolean ignore);
 
     /**
      * Populate the given metadata with default settings.

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataInheritanceComparator.java Fri Nov  3 15:15:08 2006
@@ -16,7 +16,8 @@
 package org.apache.openjpa.meta;
 
 /**
- * Comparator that keeps metadatas in inheritance order.
+ * Comparator that keeps metadatas in inheritance order.  Also places relation
+ * types used as primary keys before the primary key field owner types.
  *
  * @author Abe White
  * @nojavadoc
@@ -28,5 +29,31 @@
         if (elem == null)
             return null;
         return ((ClassMetaData) elem).getDescribedType();
+    }
+
+    public int compare(Object o1, Object o2) {
+        if (o1 == o2)
+            return 0;
+        if (o1 == null)
+            return -1;
+        if (o2 == null)
+            return 1;
+
+        ClassMetaData m1 = (ClassMetaData) o1;
+        ClassMetaData m2 = (ClassMetaData) o2;
+
+        FieldMetaData[] fmds = m1.getDeclaredFields();
+        for (int i = 0; i < fmds.length; i++) {
+            if (fmds[i].isPrimaryKey() && m2.getDescribedType().
+                isAssignableFrom(fmds[i].getDeclaredType()))
+                return 1;
+        }
+        fmds = m2.getDeclaredFields();
+        for (int i = 0; i < fmds.length; i++) {
+            if (fmds[i].isPrimaryKey() && m1.getDescribedType().
+                isAssignableFrom(fmds[i].getDeclaredType()))
+                return -1;
+        }
+        return super.compare(o1, o2);
     }
 }

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java Fri Nov  3 15:15:08 2006
@@ -483,6 +483,8 @@
         // load mapping data
         for (int i = 0; i < resolved.size(); i++)
             loadMapping((ClassMetaData) resolved.get(i));
+        for (int i = 0; i < resolved.size(); i++)
+            preMapping((ClassMetaData) resolved.get(i));
 
         // resolve mappings
         boolean err = true;
@@ -499,7 +501,6 @@
                 re = new MetaDataException(_loc.get("resolve-errs")).
                     setNestedThrowables((Throwable[]) _errs.toArray
                         (new Exception[_errs.size()]));
-            ;
             _errs.clear();
             throw re;
         }
@@ -540,6 +541,13 @@
                     meta.getPCSuperclass()));
         }
 
+        // resolve relation primary key fields for mapping dependencies
+        FieldMetaData[] fmds = meta.getDeclaredFields();
+        for (int i = 0; i < fmds.length; i++)
+            if (fmds[i].isPrimaryKey())
+                getMetaData(fmds[i].getDeclaredType(), 
+                    meta.getEnvClassLoader(), false);
+
         // resolve metadata; if we're not in the process of resolving
         // others, this will return the set of interrelated metas that
         // resolved
@@ -571,10 +579,17 @@
                 } catch (RuntimeException re) {
                     removeMetaData(meta);
                     _errs.add(re);
-                    return;
                 }
             }
         }
+    }
+
+    /**
+     * Pre-mapping preparation.
+     */
+    private void preMapping(ClassMetaData meta) {
+        if ((meta.getResolve() & MODE_MAPPING) != 0)
+            return;
 
         // prepare mappings for resolve; if not resolving mappings, then
         // make sure any superclass fields defined in metadata are resolved

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/NoneMetaDataFactory.java Fri Nov  3 15:15:08 2006
@@ -112,6 +112,10 @@
         return false;
     }
 
+    public boolean isDataStoreObjectIdFieldUnwrapped() {
+        return false;
+    }
+
     public void populate(ClassMetaData meta, int access) {
     }
 

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ProxySetupStateManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ProxySetupStateManager.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ProxySetupStateManager.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ProxySetupStateManager.java Fri Nov  3 15:15:08 2006
@@ -81,6 +81,10 @@
         }
     }
 
+    public Object getPCPrimaryKey(Object oid, int field) {
+        throw new UnsupportedOperationException();
+    }
+
     public byte replaceFlags() {
         throw new InternalException();
     }

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java?view=diff&rev=471045&r1=471044&r2=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ApplicationIds.java Fri Nov  3 15:15:08 2006
@@ -44,6 +44,9 @@
     /**
      * Return the primary key values for the given object id. The values
      * will be returned in the same order as the metadata primary key fields.
+     * Values for PC primary key fields will be the primarky key value or
+     * oid value of the related instance (depending on 
+     * {@link FieldMetaData#isObjectIdFieldIdOfPC}).
      */
     public static Object[] toPKValues(Object oid, ClassMetaData meta) {
         if (meta == null)
@@ -88,8 +91,7 @@
                 if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) {
                     field = oidType.getField(fmds[i].getName());
                     pks[i] = field.get(oid);
-                } else // property
-                {
+                } else { // property
                     meth = ImplHelper.getGetter(oidType, fmds[i].getName());
                     pks[i] = meth.invoke(oid, (Object[]) null);
                 }
@@ -104,6 +106,9 @@
 
     /**
      * Return a new object id constructed from the given primary key values.
+     * Values for PC primary key fields should be the primarky key value or
+     * oid value of the related instance (depending on 
+     * {@link FieldMetaData#isObjectIdFieldIdOfPC}).
      */
     public static Object fromPKValues(Object[] pks, ClassMetaData meta) {
         if (meta == null || pks == null)
@@ -112,7 +117,7 @@
         boolean convert = !meta.getRepository().getConfiguration().
             getCompatibilityInstance().getStrictIdentityValues();
         if (meta.isOpenJPAIdentity()) {
-            int type = meta.getPrimaryKeyFields()[0].getDeclaredTypeCode();
+            int type = meta.getPrimaryKeyFields()[0].getObjectIdFieldTypeCode();
             Object val = (convert) ? JavaTypes.convert(pks[0], type) : pks[0];
             switch (type) {
                 case JavaTypes.BYTE:
@@ -148,6 +153,7 @@
                 case JavaTypes.DATE:
                     return new DateId(meta.getDescribedType(), (Date) val);
                 case JavaTypes.OID:
+                case JavaTypes.OBJECT:
                     return new ObjectId(meta.getDescribedType(), val);
                 default:
                     throw new InternalException();
@@ -182,9 +188,8 @@
                 if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) {
                     field = oidType.getField(fmds[i].getName());
                     field.set(copy, (convert) ? JavaTypes.convert(pks[i],
-                        fmds[i].getDeclaredTypeCode()) : pks[i]);
-                } else // property
-                {
+                        fmds[i].getObjectIdFieldTypeCode()) : pks[i]);
+                } else { // property
                     if (paramTypes == null)
                         paramTypes = new Class[1];
                     paramTypes[0] = fmds[i].getDeclaredType();
@@ -193,7 +198,7 @@
                     if (params == null)
                         params = new Object[1];
                     params[0] = (convert) ? JavaTypes.convert(pks[i],
-                        fmds[i].getDeclaredTypeCode()) : pks[i];
+                        fmds[i].getObjectIdFieldTypeCode()) : pks[i];
                     meth.invoke(copy, params);
                 }
             }
@@ -218,7 +223,7 @@
             Class cls = meta.getDescribedType();
             OpenJPAId koid = (OpenJPAId) oid;
             FieldMetaData pk = meta.getPrimaryKeyFields()[0];
-            switch (pk.getDeclaredTypeCode()) {
+            switch (pk.getObjectIdFieldTypeCode()) {
                 case JavaTypes.BYTE:
                 case JavaTypes.BYTE_OBJ:
                     return new ByteId(cls, ((ByteId) oid).getId(),
@@ -248,6 +253,9 @@
                     if (embed != null)
                         inner = copy(inner, embed, embed.getFields());
                     return new ObjectId(cls, inner, koid.hasSubclasses());
+                case JavaTypes.OBJECT:
+                    return new ObjectId(cls, koid.getIdObject(), 
+                        koid.hasSubclasses());
                 default:
                     throw new InternalException();
             }
@@ -256,10 +264,11 @@
         // create a new pc instance of the right type, set its key fields
         // to the original oid values, then copy its key fields to a new
         // oid instance
-        if (!Modifier.isAbstract(meta.getDescribedType().getModifiers())) {
-            Class type = meta.getDescribedType();
-            if (meta.getInterfaceImpl() != null)
-                type = meta.getInterfaceImpl();
+        if (!Modifier.isAbstract(meta.getDescribedType().getModifiers())
+            && !hasPCPrimaryKeyFields(meta)) {
+            Class type = meta.getInterfaceImpl();
+            if (type == null)
+                type = meta.getDescribedType();
             PersistenceCapable pc = PCRegistry.newInstance(type, null, oid, 
                  false);
             Object copy = pc.pcNewObjectIdInstance();
@@ -277,6 +286,18 @@
     }
 
     /**
+     * Return true if any of the given type's primary key fields are 
+     * persistent objects.
+     */
+    private static boolean hasPCPrimaryKeyFields(ClassMetaData meta) {
+        FieldMetaData[] fmds = meta.getPrimaryKeyFields();
+        for (int i = 0; i < fmds.length; i++)
+            if (fmds[i].getDeclaredTypeCode() == JavaTypes.PC)
+                return true;
+        return false;
+    }
+
+    /**
      * Copy the given identity object using reflection.
      */
     private static Object copy(Object oid, ClassMetaData meta,
@@ -284,7 +305,6 @@
         if (oid == null)
             return null;
 
-        // default to using reflection
         Class oidType = oid.getClass();
         try {
             Object copy = oidType.newInstance();
@@ -300,11 +320,10 @@
                 if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD) {
                     field = oidType.getField(fmds[i].getName());
                     field.set(copy, field.get(oid));
-                } else // property
-                {
+                } else { // property
                     if (paramTypes == null)
                         paramTypes = new Class[1];
-                    paramTypes[0] = fmds[i].getDeclaredType();
+                    paramTypes[0] = fmds[i].getObjectIdFieldType();
                     cap = StringUtils.capitalize(fmds[i].getName());
                     meth = oidType.getMethod("set" + cap, paramTypes);
                     if (params == null)
@@ -323,6 +342,32 @@
     }
 
     /**
+     * Return the given primary key field value from the given oid.
+     */
+    public static Object get(Object oid, FieldMetaData fmd) {
+        if (oid == null)
+            return null;
+        if (oid instanceof OpenJPAId)
+            return ((OpenJPAId) oid).getIdObject();
+
+        ClassMetaData meta = fmd.getDefiningMetaData();
+        Class oidType = oid.getClass();
+        try {
+            if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
+                return oidType.getField(fmd.getName()).get(oid);
+
+            // property
+            String cap = StringUtils.capitalize(fmd.getName());
+            return ImplHelper.getGetter(oidType, cap).
+                invoke(oid, (Object[]) null);
+        } catch (OpenJPAException ke) {
+            throw ke;
+        } catch (Throwable t) {
+            throw new GeneralException(t);
+        }
+    }
+
+    /**
      * Generate an application id based on the current primary key field state
      * of the given instance.
      */
@@ -502,9 +547,14 @@
 
         private Object retrieve(int field) {
             Object val = _store[_index++];
-            if (_meta != null)
-                val = JavaTypes.convert(val, _meta.getField(field).
-                    getDeclaredTypeCode());
+            if (_meta != null) {
+                FieldMetaData fmd = _meta.getField(field);
+                if (fmd.getDeclaredTypeCode() != JavaTypes.PC)
+                    val = JavaTypes.convert(val, fmd.getDeclaredTypeCode());
+                else
+                    val = JavaTypes.convert(val, JavaTypes.getTypeCode(fmd.
+                        getObjectIdFieldType()));
+            }
             return val;
 		}
 	}

Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/BasicEntity.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/BasicEntity.java?view=auto&rev=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/BasicEntity.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/BasicEntity.java Fri Nov  3 15:15:08 2006
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.persistence.relations;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Version;
+
+@Entity
+public class BasicEntity {
+
+    @Id
+    @GeneratedValue
+    private long id;
+
+    private String name;
+
+    @ManyToOne
+    private BasicEntity rel;
+
+    @Version
+    private Integer optLock;
+
+    public long getId() { 
+        return id; 
+    }
+
+    public String getName() { 
+        return name; 
+    }
+
+    public void setName(String name) { 
+        this.name = name; 
+    }
+
+    public BasicEntity getRel() { 
+        return rel; 
+    }
+
+    public void setRel(BasicEntity rel) { 
+        this.rel = rel; 
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/BasicEntity.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/DataStoreBasicEntity.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/DataStoreBasicEntity.java?view=auto&rev=471045
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/DataStoreBasicEntity.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/DataStoreBasicEntity.java Fri Nov  3 15:15:08 2006
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.persistence.relations;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Version;
+
+import org.apache.openjpa.persistence.DataStoreId;
+
+@Entity
+@DataStoreId
+public class DataStoreBasicEntity {
+
+    private String name;
+
+    @ManyToOne
+    private BasicEntity rel;
+
+    @Version
+    private Integer optLock;
+
+    public String getName() { 
+        return name; 
+    }
+
+    public void setName(String name) { 
+        this.name = name; 
+    }
+
+    public BasicEntity getRel() { 
+        return rel; 
+    }
+
+    public void setRel(BasicEntity rel) { 
+        this.rel = rel; 
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/DataStoreBasicEntity.java
------------------------------------------------------------------------------
    svn:executable = *