Author: jason.greene(a)jboss.com
Date: 2007-09-20 19:36:35 -0400 (Thu, 20 Sep 2007)
New Revision: 4494
Added:
pojo/trunk/src/main/java/org/jboss/cache/pojo/util/Instantiator.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/util/PrivilegedCode.java
pojo/trunk/src/test/java/org/jboss/cache/pojo/NoZeroArgConstructorTest.java
Modified:
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CachedType.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/memory/FieldPersistentReference.java
pojo/trunk/src/main/java/org/jboss/cache/pojo/memory/MethodPersistentReference.java
Log:
PCACHE-3 Add support for objects with no-arg constructors
PCACHE-4 Use privileged actions
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java 2007-09-20
19:01:31 UTC (rev 4493)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/AdvisedPojoHandler.java 2007-09-20
23:36:35 UTC (rev 4494)
@@ -26,6 +26,8 @@
import org.jboss.cache.pojo.interceptors.dynamic.CacheFieldInterceptor;
import org.jboss.cache.pojo.memory.FieldPersistentReference;
import org.jboss.cache.pojo.util.AopUtil;
+import org.jboss.cache.pojo.util.Instantiator;
+import org.objenesis.ObjenesisStd;
/**
* Handling the advised pojo operations. No consideration of object graph here.
@@ -49,20 +51,13 @@
util_ = util;
}
- public Object get(Fqn fqn, Class clazz, PojoInstance pojoInstance)
+ public Object get(Fqn<?> fqn, Class<?> clazz, PojoInstance pojoInstance)
throws CacheException
{
CachedType type = pCache_.getCachedType(clazz);
- Object obj = null;
- try
- {
- obj = clazz.newInstance();
- // TODO Need to populate the object from the cache as well.
- }
- catch (Exception e)
- {
- throw new CacheException("failed creating instance of " +
clazz.getName(), e);
- }
+ Object obj =Instantiator.newInstance(clazz);
+
+ // TODO Need to populate the object from the cache as well.
// Insert interceptor at runtime
InstanceAdvisor advisor = ((Advised) obj)._getInstanceAdvisor();
CacheFieldInterceptor interceptor = new CacheFieldInterceptor(pCache_, fqn, type);
@@ -71,7 +66,7 @@
return obj;
}
- void put(Fqn fqn, Fqn referencingFqn, Object obj) throws CacheException
+ void put(Fqn<?> fqn, Fqn<?> referencingFqn, Object obj) throws
CacheException
{
CachedType type = pCache_.getCachedType(obj.getClass());
// We have a clean slate then.
@@ -155,7 +150,7 @@
}
}
- Object remove(Fqn fqn, Object result, Class clazz) throws CacheException
+ Object remove(Fqn<?> fqn, Object result, Class<?> clazz) throws
CacheException
{
CachedType type = pCache_.getCachedType(clazz);
InstanceAdvisor advisor = ((Advised) result)._getInstanceAdvisor();
Modified: pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CachedType.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CachedType.java 2007-09-20 19:01:31
UTC (rev 4493)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/impl/CachedType.java 2007-09-20 23:36:35
UTC (rev 4494)
@@ -18,6 +18,7 @@
import org.jboss.aop.joinpoint.FieldInvocation;
import org.jboss.cache.pojo.memory.FieldPersistentReference;
import org.jboss.cache.pojo.memory.PersistentReference;
+import org.jboss.cache.pojo.util.PrivilegedCode;
/**
* Represent a cached object type, e.g., whether it is <b>primitive</b> or
not.
@@ -82,7 +83,7 @@
private static boolean isImmediate(Class clazz)
{
- // Treat enums as a simple type since they serialize to a simple string
+ // Treat enums as a simple type since they serialize to a simple string
return immediates.contains(clazz) || Enum.class.isAssignableFrom(clazz);
}
@@ -210,7 +211,7 @@
Field f = classFields[i];
if (isNonReplicatable(f)) continue;
- f.setAccessible(true);
+ PrivilegedCode.setAccessible(f);
FieldPersistentReference persistentRef = new FieldPersistentReference(f,
PersistentReference.REFERENCE_SOFT);
Modified:
pojo/trunk/src/main/java/org/jboss/cache/pojo/memory/FieldPersistentReference.java
===================================================================
---
pojo/trunk/src/main/java/org/jboss/cache/pojo/memory/FieldPersistentReference.java 2007-09-20
19:01:31 UTC (rev 4493)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/memory/FieldPersistentReference.java 2007-09-20
23:36:35 UTC (rev 4494)
@@ -24,6 +24,8 @@
import java.lang.reflect.Field;
+import org.jboss.cache.pojo.util.PrivilegedCode;
+
/**
* Creates a persistentReference for Fields
*
@@ -48,7 +50,7 @@
if ((returnValue = internalGet()) != null) return returnValue;
Field field = getMappedClass().getDeclaredField(name);
- field.setAccessible(true);
+ PrivilegedCode.setAccessible(field);
buildReference(field);
return field;
}
Modified:
pojo/trunk/src/main/java/org/jboss/cache/pojo/memory/MethodPersistentReference.java
===================================================================
---
pojo/trunk/src/main/java/org/jboss/cache/pojo/memory/MethodPersistentReference.java 2007-09-20
19:01:31 UTC (rev 4493)
+++
pojo/trunk/src/main/java/org/jboss/cache/pojo/memory/MethodPersistentReference.java 2007-09-20
23:36:35 UTC (rev 4494)
@@ -24,6 +24,8 @@
import java.lang.reflect.Method;
+import org.jboss.cache.pojo.util.PrivilegedCode;
+
/**
* A reference to a field.
* In case the reference is released, the reference will be reconstructed
@@ -50,7 +52,7 @@
if ((returnValue = internalGet()) != null) return returnValue;
Method aMethod = getMappedClass().getDeclaredMethod(name, getArguments());
- aMethod.setAccessible(true);
+ PrivilegedCode.setAccessible(aMethod);
buildReference(aMethod);
return aMethod;
}
Added: pojo/trunk/src/main/java/org/jboss/cache/pojo/util/Instantiator.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/util/Instantiator.java
(rev 0)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/util/Instantiator.java 2007-09-20
23:36:35 UTC (rev 4494)
@@ -0,0 +1,94 @@
+package org.jboss.cache.pojo.util;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.jboss.cache.CacheException;
+
+public class Instantiator
+{
+ private static abstract class Allocator
+ {
+ public Object allocate(Class<?> c) throws Exception
+ {
+ Constructor<?> constructor = c.getDeclaredConstructor();
+ PrivilegedCode.setAccessible(constructor);
+ return constructor.newInstance();
+ }
+ }
+
+ private static final Allocator allocator;
+
+ static
+ {
+ // Currently only Sun and Mac JVMs are suported
+ Allocator a = createUnsafeAllocator();
+ allocator = a != null ? a : createDefaultAllocator();
+ }
+
+
+ public static Object newInstance(Class<?> c) throws CacheException
+ {
+ try
+ {
+ return allocator.allocate(c);
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("failed creating instance of " + c.getName(),
e);
+ }
+ }
+
+ private static Allocator createUnsafeAllocator()
+ {
+ Allocator allocator = null;
+ try
+ {
+ final Class<?> clazz = Class.forName("sun.misc.Unsafe");
+ final Field field = clazz.getDeclaredField("theUnsafe");
+ PrivilegedCode.setAccessible(field);
+ final Object object = field.get(null);
+ final Method method = clazz.getMethod("allocateInstance",
Class.class);
+
+ allocator = new Allocator()
+ {
+ public Object allocate(Class<?> c) throws Exception
+ {
+ try
+ {
+ return super.allocate(c);
+ }
+ catch (Exception e)
+ {
+ }
+ return method.invoke(object, c);
+ }
+ };
+ }
+ catch (Exception e)
+ {
+ }
+
+ return allocator;
+ }
+
+ private static Allocator createDefaultAllocator()
+ {
+ return new Allocator()
+ {
+
+ public Object allocate(Class<?> c) throws Exception
+ {
+ try
+ {
+ return super.allocate(c);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("A noarg constructor is required
on this JVM", e);
+ }
+ }
+ };
+ }
+}
Added: pojo/trunk/src/main/java/org/jboss/cache/pojo/util/PrivilegedCode.java
===================================================================
--- pojo/trunk/src/main/java/org/jboss/cache/pojo/util/PrivilegedCode.java
(rev 0)
+++ pojo/trunk/src/main/java/org/jboss/cache/pojo/util/PrivilegedCode.java 2007-09-20
23:36:35 UTC (rev 4494)
@@ -0,0 +1,28 @@
+package org.jboss.cache.pojo.util;
+
+import java.lang.reflect.AccessibleObject;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Performs privileged actions
+ *
+ * @author Jason T. Greene
+ */
+public class PrivilegedCode
+{
+ public static void setAccessible(final AccessibleObject object)
+ {
+ if (object.isAccessible())
+ return;
+
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ object.setAccessible(true);
+ return null;
+ }
+ });
+ }
+}
Added: pojo/trunk/src/test/java/org/jboss/cache/pojo/NoZeroArgConstructorTest.java
===================================================================
--- pojo/trunk/src/test/java/org/jboss/cache/pojo/NoZeroArgConstructorTest.java
(rev 0)
+++ pojo/trunk/src/test/java/org/jboss/cache/pojo/NoZeroArgConstructorTest.java 2007-09-20
23:36:35 UTC (rev 4494)
@@ -0,0 +1,100 @@
+package org.jboss.cache.pojo;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.config.Configuration.CacheMode;
+import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
+import org.jboss.cache.pojo.annotation.Replicable;
+import org.testng.AssertJUnit;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+/**
+ * Verifies that objects can be constructed without a public zero-arg constructor.
+ *
+ * @author Jason T. Greene
+ */
+@Test(groups = {"functional"})
+public class NoZeroArgConstructorTest
+{
+ Log log = LogFactory.getLog(NoZeroArgConstructorTest.class);
+ PojoCache cache, cache1;
+
+ @BeforeTest(alwaysRun = true)
+ protected void setUp() throws Exception
+ {
+ log.info("setUp() ....");
+ boolean toStart = false;
+ cache =
PojoCacheFactory.createCache(UnitTestCacheConfigurationFactory.createConfiguration(CacheMode.REPL_SYNC),
toStart);
+ cache.start();
+ cache1 =
PojoCacheFactory.createCache(UnitTestCacheConfigurationFactory.createConfiguration(CacheMode.REPL_SYNC),
toStart);
+ cache1.start();
+ }
+
+ @AfterTest(alwaysRun = true)
+ protected void tearDown() throws Exception
+ {
+ cache.stop();
+ cache1.stop();
+ }
+
+ @Replicable
+ public static class PrivateConstructor
+ {
+ private int x;
+ private PrivateConstructor()
+ {
+ }
+
+ public void setX(int x)
+ {
+ this.x = x;
+ }
+
+ public int getX()
+ {
+ return x;
+ }
+ }
+
+ @Replicable
+ public static class TwoArgConstructor
+ {
+ private int x;
+ public TwoArgConstructor(double one, int two)
+ {
+ }
+
+ public void setX(int x)
+ {
+ this.x = x;
+ }
+
+ public int getX()
+ {
+ return x;
+ }
+ }
+
+ public void testPrivateConstructor()
+ {
+ PrivateConstructor priv = new PrivateConstructor();
+ priv.setX(5);
+ cache.attach("/foo/private", priv);
+ PrivateConstructor priv2 = (PrivateConstructor)
cache1.find("/foo/private");
+ AssertJUnit.assertNotNull("Object not found", priv2);
+ AssertJUnit.assertEquals(priv.getX(), priv2.getX());
+ }
+
+ public void testTwoArgConstructor()
+ {
+ TwoArgConstructor cons = new TwoArgConstructor(1.0, 1);
+ cons.setX(5);
+ cache.attach("/foo/twoarg", cons);
+ TwoArgConstructor cons2 = (TwoArgConstructor)
cache1.find("/foo/twoarg");
+ AssertJUnit.assertNotNull("Object not found", cons2);
+ AssertJUnit.assertEquals(cons.getX(), cons2.getX());
+ }
+
+}
\ No newline at end of file