Author: curtisr7
Date: Sun Jul 24 12:54:45 2011
New Revision: 1150346

URL: http://svn.apache.org/viewvc?rev=1150346&view=rev
Log:
OPENJPA-2035: Allow distributed cache(s) operate without needing domain classes.

Added:
    openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/kernel/
    
openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/kernel/TestPCDataSerialization.java
Modified:
    
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Id.java
    
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java?rev=1150346&r1=1150345&r2=1150346&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java
 (original)
+++ 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java
 Sun Jul 24 12:54:45 2011
@@ -18,10 +18,11 @@
  */
 package org.apache.openjpa.kernel;
 
+import java.security.AccessController;
 import java.util.BitSet;
-import java.util.Map;
 
 import org.apache.openjpa.datacache.DataCache;
+import org.apache.openjpa.lib.util.J2DoPrivHelper;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
 
@@ -36,7 +37,8 @@ public class PCDataImpl
     extends AbstractPCData {
 
     private final Object _oid;
-    private final Class<?> _type;
+    private transient Class<?> _type;
+    private String _typeStr;
     private final String _cache;
     private final Object[] _data;
     private final BitSet _loaded;
@@ -54,6 +56,7 @@ public class PCDataImpl
     public PCDataImpl(Object oid, ClassMetaData meta, String name) {
         _oid = oid;
         _type = meta.getDescribedType();
+        _typeStr = _type.getName();
         _cache = name;
 
         int len = meta.getFields().length;
@@ -66,8 +69,21 @@ public class PCDataImpl
     }
 
     public Class<?> getType() {
+        if (_type == null) {
+            ClassLoader ccl = 
AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
+            try {
+                _type = ccl.loadClass(_typeStr);
+            } catch (ClassNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+        }
         return _type;
     }
+    
+    public void setType(Class<?> t){
+        _type = t;
+        _typeStr = t.getName();
+    }
 
     public BitSet getLoaded() {
         return _loaded;

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Id.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Id.java?rev=1150346&r1=1150345&r2=1150346&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Id.java 
(original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Id.java 
Sun Jul 24 12:54:45 2011
@@ -84,7 +84,7 @@ public final class Id
         else {
             int dash = str.indexOf(TYPE_VALUE_SEP);
             try {
-                type = Class.forName(str.substring(0, dash), true, loader);
+                setManagedInstanceType(Class.forName(str.substring(0, dash), 
true, loader));
             } catch (Throwable t) {
                 throw new UserException(_loc.get("string-id", str), t);
             }

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java?rev=1150346&r1=1150345&r2=1150346&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java
 (original)
+++ 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java
 Sun Jul 24 12:54:45 2011
@@ -19,7 +19,9 @@
 package org.apache.openjpa.util;
 
 import java.io.Serializable;
+import java.security.AccessController;
 
+import org.apache.openjpa.lib.util.J2DoPrivHelper;
 import org.apache.openjpa.lib.util.ReferenceMap;
 import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
 
@@ -29,16 +31,17 @@ import org.apache.openjpa.lib.util.concu
  * @author Steve Kim
  */
 @SuppressWarnings("serial")
-public abstract class OpenJPAId
-    implements Comparable, Serializable {
+public abstract class OpenJPAId implements Comparable, Serializable {
     public static final char TYPE_VALUE_SEP = '-';
     
     // cache the types' generated hash codes
     private static ConcurrentReferenceHashMap _typeCache =
         new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD);
 
-    protected Class type;
-    protected boolean subs = true;
+    private transient Class<?> _type;
+    private String _typeStr;
+    
+    protected boolean _subs = true;
 
     // type hash is based on the least-derived non-object class so that
     // user-given ids with non-exact types match ids with exact types
@@ -47,20 +50,31 @@ public abstract class OpenJPAId
     protected OpenJPAId() {
     }
 
-    protected OpenJPAId(Class type) {
-        this.type = type;
+    protected OpenJPAId(Class<?> type) {
+        _type = type;
+        _typeStr = type.getName();
+        
     }
 
-    protected OpenJPAId(Class type, boolean subs) {
-        this.type = type;
-        this.subs = subs;
+    protected OpenJPAId(Class<?> type, boolean subs) {
+        _type = type;
+        _typeStr = type.getName();
+        _subs = subs;
     }
 
     /**
      * Return the persistent class which this id instance represents.
      */
-    public Class getType() {
-        return type;
+    public final Class<?> getType() {
+        if (_type == null) {
+            ClassLoader ccl = 
AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
+            try {
+                _type = ccl.loadClass(_typeStr);
+            } catch (ClassNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return _type;
     }
 
     /**
@@ -68,22 +82,22 @@ public abstract class OpenJPAId
      * Defaults to true.
      */
     public boolean hasSubclasses() {
-        return subs;
+        return _subs;
     }
 
     /**
      * Set the exact type of the described instance once it is known.
      */
-    public void setManagedInstanceType(Class type) {
+    public void setManagedInstanceType(Class<?> type) {
         setManagedInstanceType(type, false);
     }
 
     /**
      * Set the exact type of the described instance once it is known.
      */
-    public void setManagedInstanceType(Class type, boolean subs) {
-        this.type = type;
-        this.subs = subs;
+    public void setManagedInstanceType(Class<?> type, boolean subs) {
+        _type = type;
+        _subs = subs;
     }
 
     /**
@@ -107,16 +121,16 @@ public abstract class OpenJPAId
      */
     public int hashCode() {
         if (_typeHash == 0) {
-            Integer typeHashInt = (Integer) _typeCache.get(type);
+            Integer typeHashInt = (Integer) _typeCache.get(getType());
             if (typeHashInt == null) {
-                Class base = type;
-                Class superclass = base.getSuperclass();
+                Class<?> base = getType();
+                Class<?> superclass = base.getSuperclass();
                 while (superclass != null && superclass != Object.class) {
                     base = base.getSuperclass();
                     superclass = base.getSuperclass();
                 }
                 _typeHash = base.hashCode();
-                _typeCache.put(type, Integer.valueOf(_typeHash));
+                _typeCache.put(getType(), Integer.valueOf(_typeHash));
             } else {
                 _typeHash = typeHashInt.intValue();
             }
@@ -131,12 +145,12 @@ public abstract class OpenJPAId
             return false;
 
         OpenJPAId id = (OpenJPAId) o;
-        return idEquals(id) && (id.type.isAssignableFrom(type)
-            || (subs && type.isAssignableFrom(id.type)));
+        return idEquals(id)
+            && (id.getType().isAssignableFrom(getType()) || (_subs && 
getType().isAssignableFrom(id.getType())));
     }
 
     public String toString() {
-        return type.getName() + TYPE_VALUE_SEP + getIdObject();
+        return getType().getName() + TYPE_VALUE_SEP + getIdObject();
     }
 
     public int compareTo(Object other) {
@@ -144,6 +158,6 @@ public abstract class OpenJPAId
             return 0;
         if (other == null)
             return 1;
-        return ((Comparable) getIdObject()).compareTo(((OpenJPAId) 
other).getIdObject ());
-       }
+        return ((Comparable) getIdObject()).compareTo(((OpenJPAId) 
other).getIdObject());
+    }
 }

Added: 
openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/kernel/TestPCDataSerialization.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/kernel/TestPCDataSerialization.java?rev=1150346&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/kernel/TestPCDataSerialization.java
 (added)
+++ 
openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/kernel/TestPCDataSerialization.java
 Sun Jul 24 12:54:45 2011
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.kernel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
+import org.apache.openjpa.enhance.DynamicStorage;
+import org.apache.openjpa.enhance.DynamicStorageGenerator;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.util.IntId;
+import org.apache.openjpa.util.OpenJPAId;
+
+/**
+ * This test ensures that we can stream a PCData and OpenJPAId to a client 
which may not have the Entities on it's
+ * classpath. In a real use case we would have multiple processes, but for the 
sake of unit testing this behavior is
+ * simulated via multiple classloaders.
+ */
+public class TestPCDataSerialization extends TestCase {
+    ClassLoader _ccl;
+
+    @Override
+    protected void setUp() throws Exception {
+        _ccl = Thread.currentThread().getContextClassLoader();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        Thread.currentThread().setContextClassLoader(_ccl);
+    }
+
+    public void test() throws Exception {
+        // Generate a new class. This will create a new class, and load it 
with a new classloader.
+        Class<?> cls = generateClass();
+        ClassLoader newLoader = cls.getClassLoader();
+        Thread.currentThread().setContextClassLoader(newLoader);
+
+        // Create moc objects
+        MetaDataRepository repo = new DummyMetaDataRepository();
+        ClassMetaData cmd = new DummyClassMetaData(cls, repo);
+
+        OpenJPAId oid = new IntId(cls, 7);
+        PCDataImpl pcdi = new PCDataImpl(oid, cmd);
+
+        // Write the object out using the newly created classloader
+        byte[] bytes = writeObject(pcdi);
+
+        // Switch contextclassloader back to the original and try to 
deserialize
+        Thread.currentThread().setContextClassLoader(_ccl);
+
+        pcdi = (PCDataImpl) readObject(bytes);
+        assertNotNull(pcdi);
+        try {
+            // This will throw a wrapped ClassNotFoundException because the 
domain class isn't available.
+            pcdi.getType();
+            fail("Should have thrown an exception.");
+        } catch (RuntimeException cnfe) {
+            // expected
+        }
+        // Write object without the class
+        bytes = writeObject(pcdi);
+
+        // Switch to loader that has the new class and make sure we find it 
again.
+        Thread.currentThread().setContextClassLoader(newLoader);
+        pcdi = (PCDataImpl) readObject(bytes);
+        assertNotNull(pcdi);
+        assertEquals(cls, pcdi.getType());
+
+    }
+
+    private byte[] writeObject(Object o) throws Exception {
+        ByteArrayOutputStream baos = null;
+        ObjectOutputStream oos = null;
+        try {
+            baos = new ByteArrayOutputStream();
+            oos = new ObjectOutputStream(baos);
+            oos.writeObject(o);
+
+            return baos.toByteArray();
+        } finally {
+            if (oos != null) {
+                oos.close();
+            }
+            if (baos != null) {
+                baos.close();
+            }
+        }
+    }
+
+    private Object readObject(byte[] bytes) throws Exception {
+        ByteArrayInputStream bais = null;
+        ObjectInputStream ois = null;
+        try {
+            bais = new ByteArrayInputStream(bytes);
+            ois = new ObjectInputStream(bais);
+            return ois.readObject();
+        } finally {
+            if (ois != null) {
+                ois.close();
+            }
+            if (bais != null) {
+                bais.close();
+            }
+        }
+    }
+
+    private Class<?> generateClass() {
+        DynamicStorageGenerator gen = new DynamicStorageGenerator();
+        int[] types =
+            new int[] { JavaTypes.BOOLEAN, JavaTypes.BYTE, JavaTypes.CHAR, 
JavaTypes.INT, JavaTypes.SHORT,
+                JavaTypes.LONG, JavaTypes.FLOAT, JavaTypes.DOUBLE, 
JavaTypes.STRING, JavaTypes.OBJECT };
+        DynamicStorage storage = gen.generateStorage(types, 
"org.apache.openjpa.enhance.Test");
+        storage = storage.newInstance();
+
+        return storage.getClass();
+    }
+
+    @SuppressWarnings("serial")
+    class DummyClassMetaData extends ClassMetaData {
+        public DummyClassMetaData(Class<?> cls, MetaDataRepository repo) {
+            super(cls, repo);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    class DummyMetaDataRepository extends MetaDataRepository {
+        @Override
+        public OpenJPAConfiguration getConfiguration() {
+            return new OpenJPAConfigurationImpl();
+        }
+    }
+}


Reply via email to