You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by sk...@apache.org on 2006/09/01 19:16:51 UTC

svn commit: r439383 - in /incubator/openjpa/trunk/openjpa-kernel/src/main: java/org/apache/openjpa/enhance/ java/org/apache/openjpa/kernel/ java/org/apache/openjpa/meta/ java/org/apache/openjpa/util/ resources/org/apache/openjpa/enhance/ resources/org/...

Author: skim
Date: Fri Sep  1 10:16:50 2006
New Revision: 439383

URL: http://svn.apache.org/viewvc?rev=439383&view=rev
Log:
Support for managed interfaces

Modified:
    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/kernel/BrokerImpl.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/InheritanceComparator.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/util/ApplicationIds.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties
    incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
    incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -90,8 +90,9 @@
 
     public static final int ENHANCE_NONE = 0;
     public static final int ENHANCE_AWARE = 2 << 0;
-    public static final int ENHANCE_PC = 2 << 1;
-    public static final int ENHANCE_OID = 2 << 2;
+    public static final int ENHANCE_INTERFACE = 2 << 1;
+    public static final int ENHANCE_PC = 2 << 2;
+    public static final int ENHANCE_OID = 2 << 3;
 
     private static final String PRE = "pc";
     private static final Class PCTYPE = PersistenceCapable.class;
@@ -127,7 +128,7 @@
      * Constructor. Supply configuration and type to enhance.
      */
     public PCEnhancer(OpenJPAConfiguration conf, Class type) {
-        this(conf, new Project().loadClass(type), null);
+        this(conf, new Project().loadClass(type), (MetaDataRepository) null);
     }
 
     /**
@@ -164,6 +165,17 @@
     }
 
     /**
+     * Constructor. Supply configuration, type, and metadata.
+     */
+    public PCEnhancer(OpenJPAConfiguration conf, BCClass type,
+        ClassMetaData meta) {
+        _pc = type;
+        _log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE);
+        _repos = meta.getRepository();
+        _meta = meta;
+    }
+
+    /**
      * Return the bytecode representation of the class being manipulated.
      */
     public BCClass getBytecode() {
@@ -266,6 +278,10 @@
             _log.trace(_loc.get("enhance-start", _pc.getType()));
 
         try {
+            // if managed interface, skip
+            if (_pc.isInterface())
+                return ENHANCE_INTERFACE;
+
             // check if already enhanced
             Class[] interfaces = _pc.getDeclaredInterfaceTypes();
             for (int i = 0; i < interfaces.length; i++) {
@@ -612,13 +628,13 @@
             String prefix = (get) ? PRE + "Get" : PRE + "Set";
             methodName = prefix + name;
             if (get) {
-                mi.setMethod(owner.getDescribedType().getName(),
+                mi.setMethod(getType(owner).getName(),
                     methodName, typeName, new String[]
-                    { owner.getDescribedType().getName() });
+                    { getType(owner).getName() });
             } else {
-                mi.setMethod(owner.getDescribedType().getName(),
+                mi.setMethod(getType(owner).getName(),
                     methodName, "void", new String[]
-                    { owner.getDescribedType().getName(), typeName });
+                    { getType(owner).getName(), typeName });
             }
         }
     }
@@ -659,6 +675,10 @@
         if (owner.getName().equals(Object.class.getName()))
             return null;
 
+        // managed interface
+        if (_meta != null && _meta.getDescribedType().isInterface())
+            return _meta;
+
         return _repos.getMetaData(owner, null, false);
     }
 
@@ -722,8 +742,9 @@
         // super.pcClearFields ()
         if (_meta.getPCSuperclass() != null) {
             code.aload().setThis();
-            code.invokespecial().setMethod(_meta.getPCSuperclass(),
-                PRE + "ClearFields", void.class, null);
+            code.invokespecial().setMethod(getType(_meta.
+                getPCSuperclassMetaData()), PRE + "ClearFields", void.class, 
+                null);
         }
 
         FieldMetaData[] fmds = _meta.getDeclaredFields();
@@ -849,7 +870,8 @@
         // return <fields> + <superclass>.pcGetManagedFieldCount ()
         code.constant().setValue(_meta.getDeclaredFields().length);
         if (_meta.getPCSuperclass() != null) {
-            code.invokestatic().setMethod(_meta.getPCSuperclass().getName(),
+            code.invokestatic().setMethod(getType(_meta.
+                getPCSuperclassMetaData()).getName(),
                 PRE + "GetManagedFieldCount", int.class.getName(), null);
             code.iadd();
         }
@@ -1039,14 +1061,15 @@
             loadManagedInstance(code, false);
             String[] args;
             if (copy) {
-                args = new String[]{ _meta.getPCSuperclass().getName(),
-                    int.class.getName() };
+                args = new String[]{ getType(_meta.getPCSuperclassMetaData()).
+                    getName(), int.class.getName() };
                 code.aload().setParam(0);
             } else
                 args = new String[]{ int.class.getName() };
             code.iload().setParam(fieldNumber);
-            code.invokespecial().setMethod(_meta.getPCSuperclass().
-                getName(), name, void.class.getName(), args);
+            code.invokespecial().setMethod(getType(_meta.
+                getPCSuperclassMetaData()).getName(), name, 
+                void.class.getName(), args);
             code.vreturn();
         } else
             throwException(code, IllegalArgumentException.class);
@@ -1442,7 +1465,8 @@
             loadManagedInstance(code, false);
             for (int i = 0; i < args.length; i++)
                 code.aload().setParam(i);
-            code.invokespecial().setMethod(_meta.getPCSuperclass().getName(),
+            code.invokespecial().setMethod(getType(_meta.
+                getPCSuperclassMetaData()).getName(),
                 PRE + "CopyKeyFieldsToObjectId", void.class.getName(), args);
         }
 
@@ -1535,7 +1559,8 @@
             loadManagedInstance(code, false);
             for (int i = 0; i < args.length; i++)
                 code.aload().setParam(i);
-            code.invokespecial().setMethod(_meta.getPCSuperclass().getName(),
+            code.invokespecial().setMethod(getType(_meta.
+                getPCSuperclassMetaData()).getName(),
                 PRE + "CopyKeyFieldsFromObjectId", void.class.getName(), args);
         }
 
@@ -1729,14 +1754,14 @@
             // new ObjectId (cls, oid)
             code.anew().setType(ObjectId.class);
             code.dup();
-            code.classconstant().setClass(_meta.getDescribedType());
+            code.classconstant().setClass(getType(_meta));
         }
 
         // new <oid class> ();
         code.anew().setType(oidType);
         code.dup();
         if (_meta.isOpenJPAIdentity() || (obj && usesClsString == Boolean.TRUE))
-            code.classconstant().setClass(_meta.getDescribedType());
+            code.classconstant().setClass(getType(_meta));
         if (obj) {
             code.aload().setParam(0);
             code.checkcast().setType(String.class);
@@ -1926,12 +1951,14 @@
         Code code = getOrCreateClassInitCode(true);
         if (_meta.getPCSuperclass() != null) {
             // pcInheritedFieldCount = <superClass>.pcGetManagedFieldCount()
-            code.invokestatic().setMethod(_meta.getPCSuperclass().getName(),
+            code.invokestatic().setMethod(getType(_meta.
+                getPCSuperclassMetaData()).getName(), 
                 PRE + "GetManagedFieldCount", int.class.getName(), null);
             code.putstatic().setField(INHERIT, int.class);
 
             // pcPCSuperclass = <superClass>;
-            code.classconstant().setClass(_meta.getPCSuperclass());
+            code.classconstant().setClass(getType(_meta.
+                getPCSuperclassMetaData()));
             code.putstatic().setField(SUPER, Class.class);
         }
 
@@ -2961,7 +2988,7 @@
         // readUnmanaged (in);
         loadManagedInstance(code, false);
         code.aload().setParam(0);
-        code.invokevirtual().setMethod(_meta.getDescribedType(),
+        code.invokevirtual().setMethod(getType(_meta),
             PRE + "ReadUnmanaged", void.class, inargs);
 
         if (detachedState) {
@@ -3013,8 +3040,9 @@
         if (parentDetachable) {
             loadManagedInstance(code, false);
             code.aload().setParam(0);
-            code.invokespecial().setMethod(_meta.getPCSuperclass(),
-                PRE + "ReadUnmanaged", void.class, inargs);
+            code.invokespecial().setMethod(getType(_meta.
+                getPCSuperclassMetaData()), PRE + "ReadUnmanaged", void.class, 
+                inargs);
         }
 
         // read declared unmanaged serializable fields
@@ -3091,7 +3119,7 @@
         Code code = meth.getCode(true);
 
         // super.writeExternal (out);
-        Class sup = _meta.getDescribedType().getSuperclass();
+        Class sup = getType(_meta).getSuperclass();
         if (!parentDetachable && Externalizable.class.isAssignableFrom(sup)) {
             loadManagedInstance(code, false);
             code.aload().setParam(0);
@@ -3102,7 +3130,7 @@
         // writeUnmanaged (out);
         loadManagedInstance(code, false);
         code.aload().setParam(0);
-        code.invokevirtual().setMethod(_meta.getDescribedType(),
+        code.invokevirtual().setMethod(getType(_meta),
             PRE + "WriteUnmanaged", void.class, outargs);
 
         JumpInstruction go2 = null;
@@ -3169,8 +3197,9 @@
         if (parentDetachable) {
             loadManagedInstance(code, false);
             code.aload().setParam(0);
-            code.invokespecial().setMethod(_meta.getPCSuperclass(),
-                PRE + "WriteUnmanaged", void.class, outargs);
+            code.invokespecial().setMethod(getType(_meta.
+                getPCSuperclassMetaData()), PRE + "WriteUnmanaged", void.class, 
+                outargs);
         }
 
         // write declared unmanaged serializable fields
@@ -3316,7 +3345,7 @@
             // static void pcSet<field> (XXX inst, <fieldtype> value)
             BCField field = _pc.getDeclaredField(fmd.getName());
             setter = _pc.declareMethod(PRE + "Set" + fmd.getName(), void.class,
-                new Class[]{ _meta.getDescribedType(), fmd.getDeclaredType() });
+                new Class[]{ getType(_meta), fmd.getDeclaredType() });
             setter.setAccessFlags(field.getAccessFlags()
                 & ~Constants.ACCESS_TRANSIENT & ~Constants.ACCESS_VOLATILE);
             setter.setStatic(true);
@@ -3338,6 +3367,17 @@
     }
 
     /**
+     * Return the concrete type for the given class, i.e. impl for managed
+     * interfaces
+     */
+    public Class getType(ClassMetaData meta) {
+        if (meta.getInterfaceImpl() != null)
+            return meta.getInterfaceImpl();
+        return meta.getDescribedType();
+    }
+
+
+    /**
      * Move code-related attributes from one method to another.
      */
     private static void transferCodeAttributes(BCMethod from, BCMethod to) {
@@ -3479,6 +3519,8 @@
             status = enhancer.run();
             if (status == ENHANCE_NONE)
                 log.info(_loc.get("enhance-norun"));
+            else if (status == ENHANCE_INTERFACE)
+                log.info(_loc.get("enhance-interface"));
             else if (status == ENHANCE_AWARE) {
                 log.info(_loc.get("enhance-aware"));
                 enhancer.record();

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -2494,6 +2494,9 @@
 
             PersistenceCapable copy;
             PCState state;
+            Class type = meta.getDescribedType();
+            if (type.isInterface())
+                type = meta.getInterfaceImpl();
             if (obj != null) {
                 // give copy and the original instance the same state manager
                 // so that we can copy fields from one to the other
@@ -2512,8 +2515,7 @@
                     // copy the instance.  we do this even if it doesn't already
                     // have a state manager in case it is later assigned to a
                     // PC field; at that point it's too late to copy
-                    copy = PCRegistry.newInstance(meta.getDescribedType(),
-                        copySM, false);
+                    copy = PCRegistry.newInstance(type, copySM, false);
                     int[] fields = new int[meta.getFields().length];
                     for (int i = 0; i < fields.length; i++)
                         fields[i] = i;
@@ -2527,8 +2529,7 @@
                         pc.pcReplaceStateManager(null);
                 }
             } else {
-                copy = PCRegistry.newInstance(meta.getDescribedType(), sm,
-                    false);
+                copy = PCRegistry.newInstance(type, sm, false);
                 if ((_flags & FLAG_ACTIVE) != 0 && !_optimistic)
                     state = PCState.ECLEAN;
                 else
@@ -3986,8 +3987,11 @@
     public Object newInstance(Class cls) {
         assertOpen();
 
-        //### JDO2
-        if (cls.isInterface() || Modifier.isAbstract(cls.getModifiers()))
+        if (cls.isInterface()) {
+            ClassMetaData meta = _conf.getMetaDataRepositoryInstance().
+                getMetaData(cls, _loader, true);
+            cls = meta.getInterfaceImpl();
+        } else if (Modifier.isAbstract(cls.getModifiers()))
             throw new UnsupportedOperationException(_loc.get
                 ("new-abstract", cls).getMessage());
 

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -241,6 +241,8 @@
             }
             _meta = sub;
         }
+        if (cls.isInterface())
+            cls = _meta.getInterfaceImpl();
 
         PersistenceCapable inst = PCRegistry.newInstance(cls, this, _oid, true);
         if (inst == null) {

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -41,6 +41,7 @@
 
     private int _access = ClassMetaData.ACCESS_FIELD;
     private boolean _ignore = true;
+    private boolean _interface = true;
     private boolean _pcRegistry = true;
     private int _callback = CALLBACK_RETHROW;
 
@@ -170,7 +171,8 @@
      */
     private void populateFromReflection(ClassMetaData meta) {
         Member[] members;
-        if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
+        boolean iface = meta.getDescribedType().isInterface();
+        if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD && !iface)
             members = meta.getDescribedType().getDeclaredFields();
         else
             members = meta.getDescribedType().getDeclaredMethods();
@@ -263,6 +265,14 @@
     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)
             return null;
@@ -319,6 +329,10 @@
                 name, clsName, "get" + capName));
         throw new UserException(_loc.get("pc-registry-no-boolean-method",
             new String[]{ name, clsName, "get" + capName, "is" + capName }));
+    }
+
+    public Class getUnimplementedExceptionType() {
+        return UnsupportedOperationException.class;
     }
 
     /**

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -140,6 +140,8 @@
     private Boolean _openjpaId = null;
     private Boolean _extent = null;
     private Boolean _embedded = null;
+    private Boolean _interface = null;
+    private Class _impl = null;
     private int _identity = -1;
     private int _idStrategy = ValueStrategies.NONE;
     private int _accessType = ACCESS_UNKNOWN;
@@ -215,9 +217,8 @@
      * an embedded value changes its declared type.
      */
     protected void setDescribedType(Class type) {
-        if (type.isInterface())
-            throw new MetaDataException(_loc.get("interface", type));
-        if ("java.lang.Enum".equals(type.getSuperclass().getName()))
+        if (type.getSuperclass() != null && "java.lang.Enum".equals
+            (type.getSuperclass().getName()))
             throw new MetaDataException(_loc.get("enum", type));
         _type = type;
     }
@@ -670,6 +671,38 @@
     }
 
     /**
+     * Whether the type is a managed interface.
+     */
+    public boolean isManagedInterface() {
+        if (!_type.isInterface())
+            return false;
+        return _interface == null ? false : _interface.booleanValue();
+    }
+
+    /**
+     * Whether the type is a managed interface
+     */
+    public void setManagedInterface(boolean managedInterface) {
+        if (!_type.isInterface())
+            throw new MetaDataException(_loc.get("not-interface", _type));
+        _interface = managedInterface ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Return the managed interface implementor if any.
+     */
+    public Class getInterfaceImpl() {
+        return _impl;
+    }
+
+    /**
+     * Set the managed interface implementor class.
+     */
+    public void setInterfaceImpl(Class impl) {
+        _impl = impl;
+    }
+    
+    /**
      * Return the number of fields that use impl or intermediate data, in
      * order to create a compacted array for storage of said data.
      */
@@ -1481,7 +1514,19 @@
             log.trace(_loc.get((embed) ? "resolve-embed-meta" : "resolve-meta",
                 this + "@" + System.identityHashCode(this)));
 
-        if (runtime && !PersistenceCapable.class.isAssignableFrom(_type))
+        if (_type.isInterface()) {
+            if (!embed && _interface != Boolean.TRUE)
+                throw new MetaDataException(_loc.get("interface", _type));
+
+            if (runtime) {
+                _impl = _repos.getImplGenerator().createImpl(this);
+                if (!embed)
+                    _repos.setInterfaceImpl(this, _impl);
+            }
+        }
+
+        if (runtime && !_type.isInterface() && 
+            !PersistenceCapable.class.isAssignableFrom(_type))
             throw new MetaDataException(_loc.get("not-enhanced", _type));
 
         // are we the target of an embedded value?
@@ -2113,6 +2158,8 @@
         _objectId = meta.getObjectIdType();
         _extent = (meta.getRequiresExtent()) ? Boolean.TRUE : Boolean.FALSE;
         _embedded = (meta.isEmbeddedOnly()) ? Boolean.TRUE : Boolean.FALSE;
+        _interface = (meta.isManagedInterface()) ? Boolean.TRUE : Boolean.FALSE;
+        _impl = meta.getInterfaceImpl();
         _identity = meta.getIdentityType();
         _idStrategy = meta.getIdentityStrategy();
         _seqName = meta.getIdentitySequenceName();

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InheritanceComparator.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InheritanceComparator.java?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InheritanceComparator.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InheritanceComparator.java Fri Sep  1 10:16:50 2006
@@ -62,8 +62,14 @@
 
         int i1 = levels(c1);
         int i2 = levels(c2);
-        if (i1 == i2)
+        if (i1 == i2) {
+            // sort simple interfaces as well as simple order test will fail.
+            if (c1.isAssignableFrom(o2.getClass()))
+                return -1;
+            if (c2.isAssignableFrom(o1.getClass()))
+                return 1;
             return c1.getName().compareTo(c2.getName());
+        }
         return i1 - i2;
     }
 

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -51,6 +51,12 @@
     public void setIgnoreNonPersistent(boolean ignore);
 
     /**
+     * Whether declared interfaces of a class are treated as persistent
+     * types. Defaults to true.
+     */
+    public boolean isDeclaredInterfacePersistent();
+
+    /**
      * Populate the given metadata with default settings.
      *
      * @param access access type constant from {@link ClassMetaData}
@@ -61,4 +67,10 @@
      * Return the backing member for the given field metadata.
      */
     public Member getBackingMember(FieldMetaData field);
+
+    /**
+     * Return a runtime exception class to throw for un-implemented
+     * managed interface methods.
+     */
+    public Class getUnimplementedExceptionType();
 }

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -25,7 +25,11 @@
     extends InheritanceComparator {
 
     protected Class toClass(Object elem) {
-        return (elem == null) ? null
-            : ((ClassMetaData) elem).getDescribedType();
+        if (elem == null)
+            return null;
+        ClassMetaData meta = (ClassMetaData) elem;
+        if (meta.getInterfaceImpl() != null)
+            return meta.getInterfaceImpl();
+        return meta.getDescribedType();
     }
 }

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -105,6 +105,7 @@
     private final Map _metas = new HashMap();
     private final Map _oids = Collections.synchronizedMap(new HashMap());
     private final Map _impls = Collections.synchronizedMap(new HashMap());
+    private final Map _ifaces = Collections.synchronizedMap(new HashMap());
     private final Map _queries = new HashMap();
     private final Map _seqs = new HashMap();
     private final Map _aliases = Collections.synchronizedMap(new HashMap());
@@ -116,6 +117,7 @@
     private OpenJPAConfiguration _conf = null;
     private Log _log = null;
     private MetaDataFactory _factory = null;
+    private InterfaceImplGenerator _implGen = null;
     private int _resMode = MODE_META | MODE_MAPPING;
     private int _sourceMode = MODE_META | MODE_MAPPING | MODE_QUERY;
     private int _validate = VALIDATE_META | VALIDATE_UNENHANCED;
@@ -541,6 +543,18 @@
                 } else
                     sup = sup.getSuperclass();
             }
+            if (meta.getDescribedType().isInterface()) {
+                Class[] sups = meta.getDescribedType().getInterfaces();
+                for (int i = 0; i < sups.length; i++) {
+                    supMeta = getMetaData(sups[i], meta.getEnvClassLoader(), 
+                        false);
+                    if (supMeta != null) {
+                        meta.setPCSuperclass(sup);
+                        meta.setPCSuperclassMetaData(supMeta);
+                        break;
+                    }
+                }
+            }
             if (_log.isTraceEnabled())
                 _log.trace(_loc.get("assigned-sup", meta,
                     meta.getPCSuperclass()));
@@ -845,12 +859,41 @@
         if (cls == null)
             return false;
         if (_metas.remove(cls) != null) {
+            Class impl = (Class) _ifaces.remove(cls);
+            if (impl != null)
+                _metas.remove(impl);
             _count--;
             return true;
         }
         return false;
     }
+
+    /**
+     * Add the given metadata as declared interface implementation.
+     */
+    public void addDeclaredInterfaceImpl(ClassMetaData meta, Class iface) {
+        synchronized (_impls) {
+            addToCollection(_impls, iface, meta.getDescribedType(), false);
+        }
+    }
+
+    /**
+     * Set the implementation for the given managed interface.
+     */
+    synchronized void setInterfaceImpl(ClassMetaData meta, Class impl) {
+        if (!meta.isManagedInterface())
+            throw new MetaDataException(_loc.get("not-managed-interface", 
+                meta, impl));
+        _ifaces.put(meta.getDescribedType(), impl);
+        _metas.put(impl, meta);
+    }
     
+    synchronized InterfaceImplGenerator getImplGenerator() {
+        if (_implGen == null)
+            _implGen = new InterfaceImplGenerator(this);
+        return _implGen;
+    }
+
     /**
      * Return the least-derived class metadata for the given application
      * identity object.
@@ -1274,6 +1317,8 @@
      * Update the list of implementations of base classes and interfaces.
      */
     private void updateImpls(Class cls, Class leastDerived, Class check) {
+        if (_factory.getDefaults().isDeclaredInterfacePersistent())
+            return;
         // allow users to query on common non-pc superclasses
         Class sup = check.getSuperclass();
         if (leastDerived == cls && sup != null && sup != Object.class) {

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -104,10 +104,18 @@
     public void setIgnoreNonPersistent(boolean ignore) {
     }
 
+    public boolean isDeclaredInterfacePersistent() {
+        return false;
+    }
+
     public void populate(ClassMetaData meta, int access) {
     }
 
     public Member getBackingMember(FieldMetaData fmd) {
+        return null;
+    }
+
+    public Class getUnimplementedExceptionType() {
         return null;
     }
 }

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?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- 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 Sep  1 10:16:50 2006
@@ -257,8 +257,11 @@
         // to the original oid values, then copy its key fields to a new
         // oid instance
         if (!Modifier.isAbstract(meta.getDescribedType().getModifiers())) {
-            PersistenceCapable pc = PCRegistry.newInstance
-                (meta.getDescribedType(), null, oid, false);
+            Class type = meta.getDescribedType();
+            if (meta.getInterfaceImpl() != null)
+                type = meta.getInterfaceImpl();
+            PersistenceCapable pc = PCRegistry.newInstance(type, null, oid, 
+                 false);
             Object copy = pc.pcNewObjectIdInstance();
             pc.pcCopyKeyFieldsToObjectId(copy);
             return copy;

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties Fri Sep  1 10:16:50 2006
@@ -24,6 +24,7 @@
 enhance-aware: The class does not have metadata - enhanced as persistence-aware.
 enhance-norun: The class is already persistence capable - no enhancement \
 	performed.
+enhance-interface: The class is a managed interface - no enhancement performed.
 enhance-usage: Usage: java org.apache.openjpa.enhance.PCEnhancer\n\
 	\t[-properties/-p <properties file or resource>]\n\
 	\t[-<property name> <property value>]*\n\

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties Fri Sep  1 10:16:50 2006
@@ -4,8 +4,8 @@
 	"{0}".
 meta-unknownid: Cannot manipulate identity of type "{0}": it''s identity type \
 	is unknown.
-new-abstract: Cannot create an instance of "{0}": abstract classes and \
-	interfaces are not yet supported.
+new-abstract: Cannot create an instance of "{0}": abstract classes are not \
+    yet supported.
 bad-new-query: Attempt to construct a query from an extent or class.  You must \
 	pass a (possibly null) query string or template to the query factory \
 	method when creating the query. 

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties?rev=439383&r1=439382&r2=439383&view=diff
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties Fri Sep  1 10:16:50 2006
@@ -18,6 +18,8 @@
 process-registered: Processing registered persistence-capable class "{0}".
 assigned-sup: Set persistence-capable superclass of "{0}" to "{1}".
 found-pcs: Found {0} classes with metadata in {1} milliseconds.
+not-managed-interface: Cannot set type "{1}" as interface "{0}" implementor. \
+    "{0}" is not a managed interface.
 unmanaged-sup-field: Superclass field "{0}" is mapped in the metadata for \
 	subclass "{1}", but is not a persistent field.
 bad-discover-class: The class "{0}" listed in the openjpa.MetaDataFactory \
@@ -180,7 +182,10 @@
 bad-update-strategy-hint: "{0}" declares a read only value of \
 	"{1}".  This is not a recognized strategy, though it closely resembles \
 	the standard strategy "{2}".  Available strategies are: {3}
-interface: Type "{0}" is an interface and therefore cannot be made persistent.
+not-interface: Can't set type "{0}" to be a managed interface as it is not \
+    and interface.
+interface: The type "{0}" is an unmanaged interface and therefore cannot be \
+    made persistent.
 enum: Type "{0}" is an enumeration and therefore cannot be made persistent.
 bad-drop: The metadata for some of the following classes may not have \
 	been dropped: {0}