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/12/13 21:14:27 UTC
svn commit: r486825 - in /incubator/openjpa/trunk/openjpa-kernel/src/main:
java/org/apache/openjpa/util/Proxies.java
java/org/apache/openjpa/util/ProxyManagerImpl.java
resources/org/apache/openjpa/util/localizer.properties
Author: awhite
Date: Wed Dec 13 12:14:26 2006
New Revision: 486825
URL: http://svn.apache.org/viewvc?view=rev&rev=486825
Log:
Option to create proxies for standard java.util types at build time. These
proxies can be serialized as proxies for use with detached state managers,
whereas runtime-generated proxies have to serialize themselves as a copied
instance of their corresponding java.util type in case they are transferred to
a different classloading environment.
Modified:
incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java
incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java
incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties
Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java?view=diff&rev=486825&r1=486824&r2=486825
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/Proxies.java Wed Dec 13 12:14:26 2006
@@ -78,13 +78,10 @@
/**
* Used by proxy types to serialize non-proxy versions.
*/
- public static Object writeReplace(Proxy proxy) {
- // we can't send dynamically-created classes to another JVM
- /*
- if (proxy == null || proxy.getOwner() == null
- || proxy.getOwner().isDetached())
+ public static Object writeReplace(Proxy proxy, boolean detachable) {
+ if (detachable && (proxy == null || proxy.getOwner() == null
+ || proxy.getOwner().isDetached()))
return proxy;
- */
return proxy.copy(proxy);
}
}
Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java?view=diff&rev=486825&r1=486824&r2=486825
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java Wed Dec 13 12:14:26 2006
@@ -24,6 +24,7 @@
import java.lang.reflect.Modifier;
import java.sql.Timestamp;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
@@ -46,6 +47,7 @@
import org.apache.openjpa.lib.util.Files;
import org.apache.openjpa.lib.util.JavaVersions;
import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.lib.util.Options;
import org.apache.openjpa.lib.util.concurrent.ConcurrentHashMap;
import serp.bytecode.BCClass;
import serp.bytecode.BCClassLoader;
@@ -331,9 +333,11 @@
// we don't lock here; ok if two proxies get generated for same type
ProxyCollection proxy = (ProxyCollection) _proxies.get(type);
if (proxy == null) {
- proxy = (ProxyCollection) instantiateProxy
- (generateProxyCollectionBytecode(type), type,
- ProxyCollection.class, null, null);
+ ClassLoader l = getMostDerivedLoader(type, ProxyCollection.class);
+ Class pcls = loadBuildTimeProxy(type, l);
+ if (pcls == null)
+ pcls = loadProxy(generateProxyCollectionBytecode(type, true),l);
+ proxy = (ProxyCollection) instantiateProxy(pcls, null, null);
_proxies.put(type, proxy);
}
return proxy;
@@ -346,8 +350,11 @@
// we don't lock here; ok if two proxies get generated for same type
ProxyMap proxy = (ProxyMap) _proxies.get(type);
if (proxy == null) {
- proxy = (ProxyMap) instantiateProxy(generateProxyMapBytecode(type),
- type, ProxyMap.class, null, null);
+ ClassLoader l = getMostDerivedLoader(type, ProxyMap.class);
+ Class pcls = loadBuildTimeProxy(type, l);
+ if (pcls == null)
+ pcls = loadProxy(generateProxyMapBytecode(type, true), l);
+ proxy = (ProxyMap) instantiateProxy(pcls, null, null);
_proxies.put(type, proxy);
}
return proxy;
@@ -360,9 +367,11 @@
// we don't lock here; ok if two proxies get generated for same type
ProxyDate proxy = (ProxyDate) _proxies.get(type);
if (proxy == null) {
- proxy = (ProxyDate) instantiateProxy
- (generateProxyDateBytecode(type), type, ProxyDate.class, null,
- null);
+ ClassLoader l = getMostDerivedLoader(type, ProxyDate.class);
+ Class pcls = loadBuildTimeProxy(type, l);
+ if (pcls == null)
+ pcls = loadProxy(generateProxyDateBytecode(type, true), l);
+ proxy = (ProxyDate) instantiateProxy(pcls, null, null);
_proxies.put(type, proxy);
}
return proxy;
@@ -375,9 +384,11 @@
// we don't lock here; ok if two proxies get generated for same type
ProxyCalendar proxy = (ProxyCalendar) _proxies.get(type);
if (proxy == null) {
- proxy = (ProxyCalendar) instantiateProxy
- (generateProxyCalendarBytecode(type), type, ProxyCalendar.class,
- null, null);
+ ClassLoader l = getMostDerivedLoader(type, ProxyCalendar.class);
+ Class pcls = loadBuildTimeProxy(type, l);
+ if (pcls == null)
+ pcls = loadProxy(generateProxyCalendarBytecode(type, true), l);
+ proxy = (ProxyCalendar) instantiateProxy(pcls, null, null);
_proxies.put(type, proxy);
}
return proxy;
@@ -388,40 +399,62 @@
*/
private ProxyBean getFactoryProxyBean(Object orig) {
// we don't lock here; ok if two proxies get generated for same type
- ProxyBean proxy = (ProxyBean) _proxies.get(orig.getClass());
- if (proxy == null && !_proxies.containsKey(orig.getClass())) {
- BCClass bc = generateProxyBeanBytecode(orig.getClass());
- if (bc == null)
- _proxies.put(orig.getClass(), null);
- else {
- BCMethod m = bc.getDeclaredMethod("<init>", (Class[]) null);
- proxy = (ProxyBean) instantiateProxy(bc, orig.getClass(),
- ProxyBean.class, findCopyConstructor(orig.getClass()),
- new Object[] {orig});
- _proxies.put(orig.getClass(), proxy);
+ Class type = orig.getClass();
+ ProxyBean proxy = (ProxyBean) _proxies.get(type);
+ if (proxy == null && !_proxies.containsKey(type)) {
+ ClassLoader l = getMostDerivedLoader(type, ProxyBean.class);
+ Class pcls = loadBuildTimeProxy(type, l);
+ if (pcls == null) {
+ BCClass bc = generateProxyBeanBytecode(type, true);
+ if (bc != null)
+ pcls = loadProxy(bc, l);
}
+ if (pcls != null)
+ proxy = (ProxyBean) instantiateProxy(pcls,
+ findCopyConstructor(type), new Object[] {orig});
+ _proxies.put(type, proxy);
}
return proxy;
}
/**
- * Instantiate the given proxy bytecode.
+ * Load the proxy class generated at build time for the given type,
+ * returning null if none exists.
+ */
+ private static Class loadBuildTimeProxy(Class type, ClassLoader loader) {
+ try {
+ return Class.forName(getProxyClassName(type, false), true, loader);
+ } catch (Throwable t) {
+ return null;
+ }
+ }
+
+ /**
+ * Load the proxy class represented by the given bytecode.
+ */
+ private Class loadProxy(BCClass bc, ClassLoader loader) {
+ BCClassLoader bcloader = new BCClassLoader(bc.getProject(), loader);
+ try {
+ return Class.forName(bc.getName(), true, bcloader);
+ } catch (Throwable t) {
+ throw new GeneralException(bc.getName()).setCause(t);
+ }
+ }
+
+ /**
+ * Instantiate the given proxy class.
*/
- private Proxy instantiateProxy(BCClass bc, Class type, Class proxy,
- Constructor cons, Object[] args) {
- BCClassLoader loader = new BCClassLoader(bc.getProject(),
- getMostDerivedClassLoader(type, proxy));
+ private Proxy instantiateProxy(Class cls, Constructor cons, Object[] args) {
try {
- Class cls = Class.forName(bc.getName(), true, loader);
if (cons != null)
return (Proxy) cls.getConstructor(cons.getParameterTypes()).
newInstance(args);
return (Proxy) cls.newInstance();
} catch (InstantiationException ie) {
- throw new UnsupportedException(_loc.get("cant-classforname",
- bc.getSuperclassName()));
+ throw new UnsupportedException(_loc.get("cant-newinstance",
+ cls.getSuperclass().getName()));
} catch (Throwable t) {
- throw new GeneralException(t);
+ throw new GeneralException(cls.getName()).setCause(t);
}
}
@@ -429,7 +462,7 @@
* Return the more derived loader of the class laoders for the given
* classes.
*/
- private static ClassLoader getMostDerivedClassLoader(Class c1, Class c2) {
+ private static ClassLoader getMostDerivedLoader(Class c1, Class c2) {
ClassLoader l1 = c1.getClassLoader();
ClassLoader l2 = c2.getClassLoader();
if (l1 == l2)
@@ -448,12 +481,11 @@
/**
* Generate the bytecode for a collection proxy for the given type.
*/
- protected BCClass generateProxyCollectionBytecode(Class type) {
+ protected BCClass generateProxyCollectionBytecode(Class type,
+ boolean runtime) {
assertNotFinal(type);
Project project = new Project();
- BCClass bc = project.loadClass(Strings.getPackageName
- (ProxyManagerImpl.class) + "." + type.getName().replace('.', '$')
- + "$" + nextProxyId() + PROXY_SUFFIX);
+ BCClass bc = project.loadClass(getProxyClassName(type, runtime));
bc.setSuperclass(type);
bc.declareInterface(ProxyCollection.class);
@@ -463,11 +495,20 @@
proxyRecognizedMethods(bc, type, ProxyCollections.class,
ProxyCollection.class);
proxySetters(bc, type);
- addWriteReplaceMethod(bc);
+ addWriteReplaceMethod(bc, runtime);
return bc;
}
/**
+ * Return the name of the proxy class to generate for the given type.
+ */
+ private static String getProxyClassName(Class type, boolean runtime) {
+ String id = (runtime) ? "$" + nextProxyId() : "";
+ return Strings.getPackageName(ProxyManagerImpl.class) + "."
+ + type.getName().replace('.', '$') + id + PROXY_SUFFIX;
+ }
+
+ /**
* Throw appropriate exception if the given type is final.
*/
private static void assertNotFinal(Class type) {
@@ -478,12 +519,10 @@
/**
* Generate the bytecode for a map proxy for the given type.
*/
- protected BCClass generateProxyMapBytecode(Class type) {
+ protected BCClass generateProxyMapBytecode(Class type, boolean runtime) {
assertNotFinal(type);
Project project = new Project();
- BCClass bc = project.loadClass(Strings.getPackageName
- (ProxyManagerImpl.class) + "." + type.getName().replace('.', '$')
- + "$" + nextProxyId() + PROXY_SUFFIX);
+ BCClass bc = project.loadClass(getProxyClassName(type, runtime));
bc.setSuperclass(type);
bc.declareInterface(ProxyMap.class);
@@ -492,19 +531,17 @@
addProxyMapMethods(bc, type);
proxyRecognizedMethods(bc, type, ProxyMaps.class, ProxyMap.class);
proxySetters(bc, type);
- addWriteReplaceMethod(bc);
+ addWriteReplaceMethod(bc, runtime);
return bc;
}
/**
* Generate the bytecode for a date proxy for the given type.
*/
- protected BCClass generateProxyDateBytecode(Class type) {
+ protected BCClass generateProxyDateBytecode(Class type, boolean runtime) {
assertNotFinal(type);
Project project = new Project();
- BCClass bc = project.loadClass(Strings.getPackageName
- (ProxyManagerImpl.class) + "." + type.getName().replace('.', '$')
- + "$" + nextProxyId() + PROXY_SUFFIX);
+ BCClass bc = project.loadClass(getProxyClassName(type, runtime));
bc.setSuperclass(type);
bc.declareInterface(ProxyDate.class);
@@ -512,19 +549,18 @@
addProxyMethods(bc, type, true);
addProxyDateMethods(bc, type);
proxySetters(bc, type);
- addWriteReplaceMethod(bc);
+ addWriteReplaceMethod(bc, runtime);
return bc;
}
/**
* Generate the bytecode for a calendar proxy for the given type.
*/
- protected BCClass generateProxyCalendarBytecode(Class type) {
+ protected BCClass generateProxyCalendarBytecode(Class type,
+ boolean runtime) {
assertNotFinal(type);
Project project = new Project();
- BCClass bc = project.loadClass(Strings.getPackageName
- (ProxyManagerImpl.class) + "." + type.getName().replace('.', '$')
- + "$" + nextProxyId() + PROXY_SUFFIX);
+ BCClass bc = project.loadClass(getProxyClassName(type, runtime));
bc.setSuperclass(type);
bc.declareInterface(ProxyCalendar.class);
@@ -532,14 +568,14 @@
addProxyMethods(bc, type, true);
addProxyCalendarMethods(bc, type);
proxySetters(bc, type);
- addWriteReplaceMethod(bc);
+ addWriteReplaceMethod(bc, runtime);
return bc;
}
/**
* Generate the bytecode for a bean proxy for the given type.
*/
- protected BCClass generateProxyBeanBytecode(Class type) {
+ protected BCClass generateProxyBeanBytecode(Class type, boolean runtime) {
if (Modifier.isFinal(type.getModifiers()))
return null;
if (ImplHelper.isManagedType(type))
@@ -558,9 +594,7 @@
}
Project project = new Project();
- BCClass bc = project.loadClass(Strings.getPackageName
- (ProxyManagerImpl.class) + "." + type.getName().replace('.', '$')
- + "$" + nextProxyId() + PROXY_SUFFIX);
+ BCClass bc = project.loadClass(getProxyClassName(type, runtime));
bc.setSuperclass(type);
bc.declareInterface(ProxyBean.class);
@@ -569,7 +603,7 @@
addProxyBeanMethods(bc, type, cons);
if (!proxySetters(bc, type))
return null;
- addWriteReplaceMethod(bc);
+ addWriteReplaceMethod(bc, runtime);
return bc;
}
@@ -1409,16 +1443,17 @@
/**
* Add a writeReplace implementation that serializes to a non-proxy type
- * unless detached.
+ * unless detached and this is a build-time generated class.
*/
- private void addWriteReplaceMethod(BCClass bc) {
+ private void addWriteReplaceMethod(BCClass bc, boolean runtime) {
BCMethod m = bc.declareMethod("writeReplace", Object.class, null);
m.makeProtected();
m.getExceptions(true).addException(ObjectStreamException.class);
Code code = m.getCode(true);
code.aload().setThis();
+ code.constant().setValue(!runtime);
code.invokestatic().setMethod(Proxies.class, "writeReplace",
- Object.class, new Class[] { Proxy.class });
+ Object.class, new Class[] { Proxy.class, boolean.class });
code.areturn();
code.calculateMaxLocals();
code.calculateMaxStack();
@@ -1474,13 +1509,20 @@
}
/**
- * Usage: java org.apache.openjpa.util.proxy.ProxyManagerImpl
- * <class name>+
+ * Usage: java org.apache.openjpa.util.proxy.ProxyManagerImpl [option]*
+ * <class name>+<br />
+ * Where the following options are recognized:
+ * <ul>
+ * <li><i>-utils/-u <number></i>: Generate proxies for the standard
+ * java.util collection, map, date, and calendar classes of the given Java
+ * version. Use 4 for Java 1.4, 5 for Java 5, etc.</li>
+ * </ul>
*
* The main method generates .class files for the proxies to the classes
- * given on the command line. The .class files are placed in the same
- * package as this class, or the current directory if the directory for this
- * class cannot be accessed.
+ * given on the command line. It writes the generated classes to beside the
+ * ProxyManagerImpl.class file if possible; otherwise it writes to the
+ * current directory. The proxy manager looks for these classes
+ * before generating its own proxies at runtime.
*/
public static void main(String[] args)
throws ClassNotFoundException, IOException {
@@ -1488,21 +1530,59 @@
dir = (dir == null) ? new File(System.getProperty("user.dir"))
: dir.getParentFile();
+ Options opts = new Options();
+ args = opts.setFromCmdLine(args);
+
+ List types = new ArrayList();
+ types.addAll(Arrays.asList(args));
+ int utils = opts.removeIntProperty("utils", "u", 0);
+ if (utils >= 4) {
+ types.addAll(Arrays.asList(new String[] {
+ java.sql.Date.class.getName(),
+ java.sql.Time.class.getName(),
+ java.sql.Timestamp.class.getName(),
+ java.util.ArrayList.class.getName(),
+ java.util.Date.class.getName(),
+ java.util.GregorianCalendar.class.getName(),
+ java.util.HashMap.class.getName(),
+ java.util.HashSet.class.getName(),
+ java.util.Hashtable.class.getName(),
+ java.util.LinkedList.class.getName(),
+ java.util.Properties.class.getName(),
+ java.util.TreeMap.class.getName(),
+ java.util.TreeSet.class.getName(),
+ java.util.Vector.class.getName(),
+ }));
+ }
+ if (utils >= 5) {
+ types.addAll(Arrays.asList(new String[] {
+ "java.util.EnumMap",
+ "java.util.IdentityHashMap",
+ "java.util.LinkedHashMap",
+ "java.util.LinkedHashSet",
+ "java.util.PriorityQueue",
+ }));
+ }
+
ProxyManagerImpl mgr = new ProxyManagerImpl();
Class cls;
BCClass bc;
- for (int i = 0; i < args.length; i++) {
- cls = Class.forName(args[i]);
+ for (int i = 0; i < types.size(); i++) {
+ cls = Class.forName((String) types.get(i));
+ if (loadBuildTimeProxy(cls, getMostDerivedLoader(cls, Proxy.class))
+ != null)
+ continue;
+
if (Collection.class.isAssignableFrom(cls))
- bc = mgr.generateProxyCollectionBytecode(cls);
+ bc = mgr.generateProxyCollectionBytecode(cls, false);
else if (Map.class.isAssignableFrom(cls))
- bc = mgr.generateProxyMapBytecode(cls);
+ bc = mgr.generateProxyMapBytecode(cls, false);
else if (Date.class.isAssignableFrom(cls))
- bc = mgr.generateProxyDateBytecode(cls);
+ bc = mgr.generateProxyDateBytecode(cls, false);
else if (Calendar.class.isAssignableFrom(cls))
- bc = mgr.generateProxyCalendarBytecode(cls);
+ bc = mgr.generateProxyCalendarBytecode(cls, false);
else
- bc = mgr.generateProxyBeanBytecode(cls);
+ bc = mgr.generateProxyBeanBytecode(cls, false);
System.out.println(bc.getName());
bc.write(new File(dir, bc.getClassName() + ".class"));
Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties?view=diff&rev=486825&r1=486824&r2=486825
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/util/localizer.properties Wed Dec 13 12:14:26 2006
@@ -49,7 +49,7 @@
"{0}". No corresponding concrete types are known.
no-proxy-abstract: Unable to create a second class object proxy for abstract \
type "{0}". You must use a concrete type or a recognized interface.
-cant-classforname: Unable to instantiate proxy for type "{0}". Make sure the \
+cant-newinstance: Unable to instantiate proxy for type "{0}". Make sure the \
class has a default constructor.
no-date-cons: Custom date type "{0}" needs a default constructor or a \
millisecond constructor.