You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by mi...@apache.org on 2009/05/29 22:06:33 UTC
svn commit: r780086 - in /openjpa/trunk: ./
openjpa-kernel/src/main/java/org/apache/openjpa/conf/
openjpa-kernel/src/main/java/org/apache/openjpa/enhance/
openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/
openjpa-persistence-jdbc/ openjpa-p...
Author: mikedd
Date: Fri May 29 20:06:29 2009
New Revision: 780086
URL: http://svn.apache.org/viewvc?rev=780086&view=rev
Log:
OPENJPA-952. Committing patch from Rick Curtis
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/DynamicEnhancementSuite.java (with props)
Modified:
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ClassRedefiner.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/InstrumentationFactory.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancerAgent.java
openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties
openjpa/trunk/openjpa-persistence-jdbc/pom.xml
openjpa/trunk/openjpa-persistence-jdbc/src/main/ant/enhancer.xml
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestGenerators.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java
openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml
openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml
openjpa/trunk/openjpa/pom.xml
openjpa/trunk/pom.xml
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java Fri May 29 20:06:29 2009
@@ -1557,7 +1557,15 @@
* @since 1.0.0
*/
public void setRuntimeUnenhancedClasses(int mode);
-
+ /**
+ * Whether OpenJPA will attempt to dynamically load the enhancement agent.
+ */
+ public boolean getDynamicEnhancementAgent();
+ /**
+ * Sets whether OpenJPA will attempt to dynamically load the enhancement
+ * agent.
+ */
+ public void setDynamicEnhancementAgent(boolean dynamic);
/**
* A comma-separted list of the plugin strings specifying the
* {@link CacheMarshaller}s to use.
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java Fri May 29 20:06:29 2009
@@ -28,6 +28,7 @@
import org.apache.openjpa.datacache.DataCacheManager;
import org.apache.openjpa.datacache.DataCacheManagerImpl;
import org.apache.openjpa.ee.ManagedRuntime;
+import org.apache.openjpa.enhance.PCEnhancerAgent;
import org.apache.openjpa.enhance.RuntimeUnenhancedClasssesModes;
import org.apache.openjpa.event.BrokerFactoryEventManager;
import org.apache.openjpa.event.OrphanedKeyAction;
@@ -165,6 +166,8 @@
new StoreFacadeTypeRegistry();
private BrokerFactoryEventManager _brokerFactoryEventManager =
new BrokerFactoryEventManager(this);
+
+ public BooleanValue dynamicEnhancementAgent;
/**
* Default constructor. Attempts to load global properties.
@@ -572,6 +575,10 @@
"getValidationFactoryInstance");
validationFactory.setDynamic(true);
+ dynamicEnhancementAgent = addBoolean("DynamicEnhancementAgent");
+ dynamicEnhancementAgent.setDefault("true");
+ dynamicEnhancementAgent.set(true);
+
// initialize supported options that some runtimes may not support
supportedOptions.add(OPTION_NONTRANS_READ);
supportedOptions.add(OPTION_OPTIMISTIC);
@@ -1605,4 +1612,10 @@
public void setValidationFactory(Object factory) {
validationFactory.set(factory);
}
+ public boolean getDynamicEnhancementAgent() {
+ return dynamicEnhancementAgent.get();
+ }
+ public void setDynamicEnhancementAgent(boolean dynamic) {
+ dynamicEnhancementAgent.set(dynamic);
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ClassRedefiner.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ClassRedefiner.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ClassRedefiner.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ClassRedefiner.java Fri May 29 20:06:29 2009
@@ -60,14 +60,15 @@
*/
public static void redefineClasses(OpenJPAConfiguration conf,
final Map<Class,byte[]> classes) {
- if (classes == null || classes.size() == 0 || !canRedefineClasses())
+ Log log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE);
+ if (classes == null || classes.size() == 0 || !canRedefineClasses(log))
return;
- Log log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE);
Instrumentation inst = null;
ClassFileTransformer t = null;
try {
- inst = InstrumentationFactory.getInstrumentation();
+ inst =
+ InstrumentationFactory.getInstrumentation(log);
Class[] array = classes.keySet().toArray(new Class[classes.size()]);
if (JavaVersions.VERSION >= 6) {
@@ -100,17 +101,7 @@
classes.get(array[i]));
inst.redefineClasses(defs);
}
- } catch (NoSuchMethodException e) {
- throw new InternalException(e);
- } catch (IllegalAccessException e) {
- throw new InternalException(e);
- } catch (InvocationTargetException e) {
- throw new UserException(e.getCause());
- } catch (IOException e) {
- throw new InternalException(e);
- } catch (ClassNotFoundException e) {
- throw new InternalException(e);
- } catch (UnmodifiableClassException e) {
+ } catch (Exception e) {
throw new InternalException(e);
} finally {
if (inst != null && t != null)
@@ -126,11 +117,11 @@
* only checks whether or not an instrumentation is available and
* if retransformation is possible.
*/
- public static boolean canRedefineClasses() {
+ public static boolean canRedefineClasses(Log log) {
if (_canRedefine == null) {
try {
Instrumentation inst = InstrumentationFactory
- .getInstrumentation();
+ .getInstrumentation(log);
if (inst == null) {
_canRedefine = Boolean.FALSE;
} else if (JavaVersions.VERSION == 5) {
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/InstrumentationFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/InstrumentationFactory.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/InstrumentationFactory.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/InstrumentationFactory.java Fri May 29 20:06:29 2009
@@ -18,12 +18,24 @@
*/
package org.apache.openjpa.enhance;
-import java.io.*;
-import java.lang.instrument.*;
-import java.lang.management.*;
-import java.lang.reflect.InvocationTargetException;
-import java.util.zip.*;
-import org.apache.openjpa.lib.util.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.lang.instrument.Instrumentation;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.util.JavaVersions;
+import org.apache.openjpa.lib.util.Localizer;
/**
@@ -35,7 +47,17 @@
public class InstrumentationFactory {
private static Instrumentation _inst;
private static boolean _dynamicallyInstall = true;
-
+ private static final String _name = InstrumentationFactory.class.getName();
+ private static final Localizer _loc = Localizer.forPackage(
+ InstrumentationFactory.class);
+
+ /**
+ * This method is not synchronized because when the agent is loaded from
+ * getInstrumentation() that method will cause agentmain(..) to be called.
+ * Synchronizing this method would cause a deadlock.
+ *
+ * @param inst The instrumentation instance to be used by this factory.
+ */
public static void setInstrumentation(Instrumentation inst) {
_inst = inst;
}
@@ -48,9 +70,13 @@
_dynamicallyInstall = val;
}
- public static synchronized Instrumentation getInstrumentation()
- throws IOException, NoSuchMethodException, IllegalAccessException,
- InvocationTargetException, ClassNotFoundException {
+ /**
+ * @param log OpenJPA log.
+ * @return null if Instrumentation can not be obtained, or if any
+ * Exceptions are encountered.
+ */
+ public static synchronized Instrumentation
+ getInstrumentation(final Log log) {
if (_inst != null || !_dynamicallyInstall)
return _inst;
@@ -58,52 +84,58 @@
if (JavaVersions.VERSION < 6)
return null;
- String agentPath = getAgentJar();
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ // If we can't find the tools.jar, we can't load the agent.
+ File toolsJar = findToolsJar(log);
+ if (toolsJar == null) {
+ return null;
+ }
+
+ Class<?> vmClass = loadVMClass(toolsJar, log);
+ if (vmClass == null) {
+ return null;
+ }
+ String agentPath = getAgentJar(log);
+ if (agentPath == null) {
+ return null;
+ }
+ loadAgent(log, agentPath, vmClass);
+ return null;
+ }// end run()
+ });
+ // If the load(...) agent call was successful, this variable will no
+ // longer be null.
+ return _inst;
+ }//end getInstrumentation()
- // first obtain the PID of the currently-running process
- // ### this relies on the undocumented convention of the RuntimeMXBean's
- // ### name starting with the PID, but there appears to be no other
- // ### way to obtain the current process' id, which we need for
- // ### the attach process
- RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
- String pid = runtime.getName();
- if (pid.indexOf("@") != -1)
- pid = pid.substring(0, pid.indexOf("@"));
-
- // JDK1.6: now attach to the current VM so we can deploy a new agent
- // ### this is a Sun JVM specific feature; other JVMs may offer
- // ### this feature, but in an implementation-dependent way
- Class vmClass = Class.forName("com.sun.tools.attach.VirtualMachine");
- Object vm = vmClass.getMethod("attach", new Class[] { String.class }).
- invoke(null, new String[] { pid });
-
- // now deploy the actual agent, which will wind up calling agentmain()
- vm.getClass().getMethod("loadAgent", new Class[] { String.class }).
- invoke(vm, new Object[] { agentPath });
-
- if (_inst != null)
- return _inst;
-
- return null;
+ /**
+ * The method that is called when a jar is added as an agent at runtime.
+ * All this method does is store the {@link Instrumentation} for
+ * later use.
+ */
+ public static void agentmain(String agentArgs, Instrumentation inst) {
+ InstrumentationFactory.setInstrumentation(inst);
}
- /**
- * Create a new jar file for the sole purpose of specifying an
- * Agent-Class to load into the JVM.
- */
- private static String getAgentJar() throws IOException {
- File file = File.createTempFile(
- InstrumentationFactory.class.getName(), ".jar");
+ /**
+ * Create a new jar file for the sole purpose of specifying an Agent-Class
+ * to load into the JVM.
+ *
+ * @return absolute path to the new jar file.
+ */
+ private static String createAgentJar() throws IOException {
+ File file =
+ File.createTempFile(InstrumentationFactory.class.getName(), ".jar");
file.deleteOnExit();
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(file));
zout.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
- PrintWriter writer = new PrintWriter
- (new OutputStreamWriter(zout));
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(zout));
- writer.println("Agent-Class: "
- + InstrumentationFactory.class.getName());
+ writer
+ .println("Agent-Class: " + InstrumentationFactory.class.getName());
writer.println("Can-Redefine-Classes: true");
writer.println("Can-Retransform-Classes: true");
@@ -113,11 +145,163 @@
}
/**
- * The method that is called when a jar is added as an agent at runtime.
- * All this method does is store the {@link Instrumentation} for
- * later use.
+ * This private worker method attempts to find [java_home]/lib/tools.jar.
+ * Note: The tools.jar is a part of the SDK, it is not present in the JRE.
+ *
+ * @return If tools.jar can be found, a File representing tools.jar. <BR>
+ * If tools.jar cannot be found, null.
*/
- public static void agentmain(String agentArgs, Instrumentation inst) {
- InstrumentationFactory.setInstrumentation(inst);
+ private static File findToolsJar(Log log) {
+ String javaHome = System.getProperty("java.home");
+ File javaHomeFile = new File(javaHome);
+
+ // IBM JDK hack -- for some reason when running on the IBM JDK, the JVM
+ // appends /jre to the java.home SystemProperty. Remove the addition to
+ // be consistent with Sun. Note: Not sure if this is something dependent
+ // on my machine. Not really that big of a deal since this isn't
+ // supported on the IBM JDK at this point.
+ File toolsJarFile =
+ new File(javaHomeFile, "lib" + File.separator + "tools.jar");
+ if (toolsJarFile.exists() == false) {
+ // If tools jar file isn't found, we may be on an IBM JDK. If the
+ // java.home property ends in /jre, try removing it to look for the
+ // tools.jar.
+ String absPath = javaHomeFile.getAbsolutePath();
+ if (absPath.endsWith(File.separator + "jre") == true) {
+ javaHomeFile = javaHomeFile.getParentFile();
+ toolsJarFile =
+ new File(javaHomeFile, "lib" + File.separator +
+ "tools.jar");
+ }
+ }
+
+ if (toolsJarFile.exists() == false) {
+ String toolsJarPath = toolsJarFile.getAbsolutePath();
+ if (log.isTraceEnabled() == true) {
+ log.trace(_name + ".findToolsJar() -- couldn't find "
+ + toolsJarPath);
+ }
+ return null;
+ }
+ return toolsJarFile;
+ }
+
+ /**
+ * This private worker method will return a fully qualified path to a jar
+ * that has this class defined as an Agent-Class in it's
+ * META-INF/manifest.mf file. Under normal circumstances the path should
+ * point to the OpenJPA jar. If running in a development environment a
+ * temporary jar file will be created.
+ *
+ * @return absolute path to the agent jar.
+ * @throws Exception
+ * if this method is unable to detect where this class was
+ * loaded from. It is unknown if this is actually possible.
+ */
+ private static String getAgentJar(Log log) {
+ // Find the name of the jar that this class was loaded from. That
+ // jar *should* be the same location as our agent.
+ File agentJarFile =
+ new File(InstrumentationFactory.class.getProtectionDomain()
+ .getCodeSource().getLocation().getFile());
+ // We're deadmeat if we can't find a file that this class
+ // was loaded from. Just return if this file doesn't exist.
+ // Note: I'm not sure if this can really happen.
+ if (agentJarFile.exists() == false) {
+ if (log.isTraceEnabled() == true) {
+ log.trace(_name + ".getAgentJar() -- Couldn't find where this "
+ + "class was loaded from!");
+ }
+ }
+ String agentJar;
+ if (agentJarFile.isDirectory() == true) {
+ // This will happen when running in eclipse as an OpenJPA
+ // developer. No one else should ever go down this path. We
+ // should log a warning here because this will create a jar
+ // in your temp directory that doesn't always get cleaned up.
+ try {
+ agentJar = createAgentJar();
+ if (log.isInfoEnabled() == true) {
+ log.info(_loc.get("temp-file-creation", agentJar));
+ }
+ } catch (IOException ioe) {
+ if (log.isTraceEnabled() == true) {
+ log.trace(_name + ".getAgentJar() caught unexpected "
+ + "exception.", ioe);
+ }
+ agentJar = null;
+ }
+ } else {
+ agentJar = agentJarFile.getAbsolutePath();
+ }
+
+ return agentJar;
+ }
+
+ /**
+ * Attach and load an agent class.
+ *
+ * @param log Log used if the agent cannot be loaded.
+ * @param agentJar absolute path to the agent jar.
+ * @param vmClass VirtualMachine.class from tools.jar.
+ */
+ private static void loadAgent(Log log, String agentJar, Class<?> vmClass) {
+ try {
+ // first obtain the PID of the currently-running process
+ // ### this relies on the undocumented convention of the
+ // RuntimeMXBean's
+ // ### name starting with the PID, but there appears to be no other
+ // ### way to obtain the current process' id, which we need for
+ // ### the attach process
+ RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
+ String pid = runtime.getName();
+ if (pid.indexOf("@") != -1)
+ pid = pid.substring(0, pid.indexOf("@"));
+
+ // JDK1.6: now attach to the current VM so we can deploy a new agent
+ // ### this is a Sun JVM specific feature; other JVMs may offer
+ // ### this feature, but in an implementation-dependent way
+ Object vm =
+ vmClass.getMethod("attach", new Class<?>[] { String.class })
+ .invoke(null, new String[] { pid });
+
+ // now deploy the actual agent, which will wind up calling
+ // agentmain()
+ vmClass.getMethod("loadAgent", new Class[] { String.class })
+ .invoke(vm, new Object[] { agentJar });
+ vmClass.getMethod("detach", new Class[] {}).invoke(vm,
+ new Object[] {});
+ } catch (Throwable t) {
+ if (log.isTraceEnabled() == true) {
+ // Log the message from the exception. Don't log the entire
+ // stack as this is expected when running on a JDK that doesn't
+ // support the Attach API.
+ log.trace(_name + ".loadAgent() caught an exception. Message: "
+ + t.getMessage());
+ }
+ }
+ }
+
+ /**
+ * This private method will create a new classloader and attempt to load the
+ * com.sun.tools.attach.VirtualMachine class from the provided toolsJar
+ * file.
+ *
+ * @return com.sun.tools.attach.VirtualMachine class <br>
+ * or null if something unexpected happened.
+ */
+ private static Class<?> loadVMClass(File toolsJar, Log log) {
+ try {
+ URLClassLoader loader =
+ new URLClassLoader(new URL[] { toolsJar.toURI().toURL() },
+ Thread.currentThread().getContextClassLoader());
+ return loader.loadClass("com.sun.tools.attach.VirtualMachine");
+ } catch (Exception e) {
+ if (log.isTraceEnabled()) {
+ log.trace(_name
+ + ".loadVMClass() failed to load the VirtualMachine class");
+ }
+ }
+ return null;
}
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java Fri May 29 20:06:29 2009
@@ -95,6 +95,21 @@
if (!PersistenceCapable.class.isAssignableFrom(cls))
unenhanced.add(cls);
if (unenhanced.size() > 0) {
+ if (PCEnhancerAgent.getLoadSuccessful() == true) {
+ // This means that the enhancer has been ran but we
+ // have some unenhanced classes. This can happen if an
+ // entity is loaded by the JVM before the EntityManger
+ // was created. Warn the user.
+ if (log.isWarnEnabled()) {
+ log.warn(_loc.get("entities-loaded-before-em"));
+ }
+ if (log.isTraceEnabled()) {
+ log.trace(ManagedClassSubclasser.class.getName()
+ + ".prepareUnenhancedClasses()"
+ + " - The following classes are unenhanced "
+ + unenhanced.toString());
+ }
+ }
Message msg = _loc.get("runtime-optimization-disabled",
unenhanced);
if (conf.getRuntimeUnenhancedClassesConstant()
@@ -106,7 +121,7 @@
return null;
}
- boolean redefine = ClassRedefiner.canRedefineClasses();
+ boolean redefine = ClassRedefiner.canRedefineClasses(log);
if (redefine)
log.info(_loc.get("enhance-and-subclass-and-redef-start",
classes));
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancerAgent.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancerAgent.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancerAgent.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancerAgent.java Fri May 29 20:06:29 2009
@@ -20,47 +20,109 @@
import java.lang.instrument.Instrumentation;
import java.security.AccessController;
-import java.util.Iterator;
import java.util.List;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.lib.conf.Configurations;
+import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Options;
import org.apache.openjpa.util.ClassResolver;
/**
- * <p>Java agent that makes persistent classes work with OpenJPA at runtime.
- * This is achieved by either running the enhancer on the classes as they
- * are loaded, or by redefining the classes on the fly.
- * The agent is launched at JVM startup from the command line:</p>
- *
- * <p><code>java -javaagent:openjpa.jar[=<options>]</code>
- * The options string should be formatted as a OpenJPA plugin, and may
- * contain any properties understood by the OpenJPA enhancer or any
- * configuration properties. For example:</p>
- *
- * <p><code>java -javaagent:openjpa.jar</code></p>
- *
- * <p>By default, if specified, the agent runs the OpenJPA enhancer on
- * all classes listed in the first persistence unit as they are loaded,
- * and redefines all other persistent classes when they are encountered.
- * To disable enhancement at class-load time and rely solely on the
- * redefinition logic, set the ClassLoadEnhancement flag to false. To
- * disable redefinition and rely solely on pre-deployment or class-load
- * enhancement, set the RuntimeRedefinition flag to false.
+ * <p>
+ * Java agent that makes persistent classes work with OpenJPA at runtime. This
+ * is achieved by either running the enhancer on the classes as they are loaded,
+ * or by redefining the classes on the fly. The agent is launched at JVM startup
+ * from the command line:
* </p>
- *
- * <p><code>java -javaagent:openjpa.jar=ClassLoadEnhancement=false</code></p>
- *
+ *
+ * <p>
+ * <code>java -javaagent:openjpa.jar[=<options>]</code> The options string
+ * should be formatted as a OpenJPA plugin, and may contain any properties
+ * understood by the OpenJPA enhancer or any configuration properties. For
+ * example:
+ * </p>
+ *
+ * <p>
+ * <code>java -javaagent:openjpa.jar</code>
+ * </p>
+ *
+ * <p>
+ * By default, if specified, the agent runs the OpenJPA enhancer on all classes
+ * listed in the first persistence unit as they are loaded, and redefines all
+ * other persistent classes when they are encountered. To disable enhancement at
+ * class-load time and rely solely on the redefinition logic, set the
+ * ClassLoadEnhancement flag to false. To disable redefinition and rely solely
+ * on pre-deployment or class-load enhancement, set the RuntimeRedefinition flag
+ * to false.
+ * </p>
+ *
+ * <p>
+ * <code>java -javaagent:openjpa.jar=ClassLoadEnhancement=false</code>
+ * </p>
+ *
* @author Abe White
* @author Patrick Linskey
*/
public class PCEnhancerAgent {
+ private static boolean loadAttempted = false;
+ private static boolean loadSuccessful = false;
+ private static boolean disableDynamicAgent = false;
+
+ /**
+ * @return True if the Agent has ran successfully. False otherwise.
+ */
+ public static synchronized boolean getLoadSuccessful() {
+ return loadSuccessful;
+ }
+ /**
+ * @return True if the dynamic agent was disabled via configuration.
+ */
+ public static void disableDynamicAgent(){
+ disableDynamicAgent=true;
+ }
+
+ /**
+ * @param log
+ * @return True if the agent is loaded successfully
+ */
+ public static synchronized boolean loadDynamicAgent(Log log) {
+ if (loadAttempted == false && disableDynamicAgent == false) {
+ Instrumentation inst =
+ InstrumentationFactory.getInstrumentation(log);
+ if (inst != null) {
+ premain("", inst);
+ } else {
+ // This needs to be set in this method AND in premain because
+ // there are two different paths that we can attempt to load the
+ // agent. One is when the user specifies a javaagent and the
+ // other is when we try to dynamically enhance.
+ loadAttempted = true;
+ }
+ }
+
+ return getLoadSuccessful();
+ }
+
public static void premain(String args, Instrumentation inst) {
+ // If the enhancer has already completed, noop. This can happen
+ // if runtime enhancement is specified via javaagent, and
+ // openJPA tries to dynamically enhance.
+ // The agent will be disabled when running in an application
+ // server.
+ synchronized (PCEnhancerAgent.class) {
+ if (loadAttempted == true) {
+ return;
+ }
+ // See the comment in loadDynamicAgent as to why we set this to true
+ // in multiple places.
+ loadAttempted = true;
+ }
+
Options opts = Configurations.parseProperties(args);
if (opts.containsKey("ClassLoadEnhancement") ||
@@ -88,6 +150,7 @@
} else {
InstrumentationFactory.setDynamicallyInstallAgent(false);
}
+ loadSuccessful = true;
}
private static void registerClassLoadEnhancer(Instrumentation inst,
Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/enhance/localizer.properties Fri May 29 20:06:29 2009
@@ -206,3 +206,9 @@
most-derived-unrelated-same-type: Methods "{0}" and "{1}" are defined in the same \
type, but the method return types do not have an interface or superclass \
inheritance relationship.
+entities-loaded-before-em: Unenhanced classes were detected even though the \
+ enhancer has ran. Ensure that the EntityManagerFactory is created prior \
+ to creating any Entities.
+temp-file-creation: The temporary file "{0}" was created and it may not get \
+ cleaned up properly.
+
Modified: openjpa/trunk/openjpa-persistence-jdbc/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/pom.xml?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/pom.xml (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/pom.xml Fri May 29 20:06:29 2009
@@ -47,6 +47,49 @@
</properties>
<profiles>
+ <!-- Profile for testing with test-dynamic-enhancer -->
+ <profile>
+ <id>test-dynamic-enhancer</id>
+
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <properties>
+ <build.enhance>false</build.enhance>
+ <test.jvm.arguments>-Dopenjpa.RuntimeUnenhancedClasses=unsupported -Xmx512m </test.jvm.arguments>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+
+ <argLine>${test.jvm.arguments}</argLine>
+ <includes><include>org/apache/openjpa/persistence/enhance/DynamicEnhancementSuite.java</include></includes>
+ <systemProperties>
+ <property>
+ <name>openjpa.Log</name>
+ <value>DefaultLevel=${openjpa.loglevel}</value>
+ </property>
+ <property>
+ <name>openjpa.ConnectionDriverName</name>
+ <value>org.apache.commons.dbcp.BasicDataSource</value>
+ </property>
+ <property>
+ <name>derby.stream.error.file</name>
+ <value>target/derby.log</value>
+ </property>
+ <property>
+ <name>openjpa.ConnectionProperties</name>
+ <value>DriverClassName=${connection.driver.name},Url=${connection.url},Username=${connection.username},Password=${connection.password},${dbcp.args}</value>
+ </property>
+ </systemProperties>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
<!-- Profile for testing with Apache Derby -->
<profile>
<id>test-derby</id>
@@ -558,6 +601,7 @@
<property name="outdir" value="${project.build.outputDirectory}" />
<property name="project.build.testOutputDirectory" value="${project.build.testOutputDirectory}" />
<property name="openjpa.loglevel" value="${openjpa.loglevel}" />
+ <property name="build.enhance" value="${build.enhance}" />
</ant>
</tasks>
</configuration>
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/main/ant/enhancer.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/main/ant/enhancer.xml?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/main/ant/enhancer.xml (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/main/ant/enhancer.xml Fri May 29 20:06:29 2009
@@ -31,8 +31,13 @@
<istrue value="${maven.test.skip}" />
</condition>
- <condition property="test.isfalse">
+ <condition property="skip.enhance">
+ <or>
<equals arg1="${test}" arg2="false" />
+ <equals arg1="${build.enhance}" arg2="false" />
+ <istrue value="${maven.test.skip}" />
+ <istrue value="${skipTests}" />
+ </or>
</condition>
<!-- =================================
@@ -40,7 +45,7 @@
================================= -->
<target name="enhance"
description="--> run the enhancer unless test=false"
- unless="test.isfalse">
+ unless="skip.enhance">
<antcall target="enhance.all.entities"
inheritall="true"
inheritrefs="true" />
@@ -51,7 +56,7 @@
================================= -->
<target name="enhance.all.entities"
description="--> enhance the test entities"
- unless="maven.test.skip.istrue">
+ unless="skip.enhance">
<echo> running enhancer</echo>
<!--
Inherited references won't be present until the task is called.
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/AbstractUnenhancedClassTest.java Fri May 29 20:06:29 2009
@@ -26,11 +26,13 @@
import java.util.List;
import java.util.Collections;
import java.lang.reflect.Field;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.JPAFacadeHelper;
import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.meta.AccessCode;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.util.ImplHelper;
@@ -40,6 +42,7 @@
public abstract class AbstractUnenhancedClassTest
extends SingleEMFTestCase {
+ Log _log;
// ##### To do:
// - clearing in pnew property-access without redefinition
// - figure out how to auto-test the redefinition code, either in Java 5
@@ -53,6 +56,7 @@
setUp(getUnenhancedClass(), getUnenhancedSubclass(), CLEAR_TABLES);
// trigger class redefinition
emf.createEntityManager().close();
+ _log = emf.getConfiguration().getLog(OpenJPAConfiguration.LOG_ENHANCE);
}
protected abstract Class<? extends UnenhancedType> getUnenhancedClass();
@@ -72,8 +76,8 @@
public void testMetaData() {
ClassMetaData meta = JPAFacadeHelper.getMetaData(emf,
getUnenhancedClass());
- assertEquals(ClassRedefiner.canRedefineClasses(),
- meta.isIntercepting());
+ assertEquals(ClassRedefiner.canRedefineClasses(_log), meta
+ .isIntercepting());
}
public void testImplHelperCalls() {
@@ -308,7 +312,7 @@
// we only expect lazy loading to work when we can redefine classes
// or when accessing a property-access record that OpenJPA created.
- if (ClassRedefiner.canRedefineClasses()
+ if (ClassRedefiner.canRedefineClasses(_log)
|| (!userDefined
&& AccessCode.isProperty(sm.getMetaData().getAccessType()))) {
@@ -360,7 +364,7 @@
// we only expect lazy loading to work when we can redefine classes
// or when accessing a property-access record that OpenJPA created.
- if (ClassRedefiner.canRedefineClasses()
+ if (ClassRedefiner.canRedefineClasses(_log)
|| AccessCode.isProperty(sm.getMetaData().getAccessType())) {
assertFalse(sm.getLoaded()
.get(sm.getMetaData().getField("lazyField").getIndex()));
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/DynamicEnhancementSuite.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/DynamicEnhancementSuite.java?rev=780086&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/DynamicEnhancementSuite.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/DynamicEnhancementSuite.java Fri May 29 20:06:29 2009
@@ -0,0 +1,268 @@
+/*
+ * 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.persistence.enhance;
+
+import javax.persistence.Persistence;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.openjpa.persistence.annotations.TestAnnotationBasics;
+import org.apache.openjpa.persistence.annotations.TestEmbeddedId;
+import org.apache.openjpa.persistence.annotations.TestEnumerated;
+import org.apache.openjpa.persistence.annotations.TestFlatInheritance;
+import org.apache.openjpa.persistence.annotations.TestGenerators;
+import org.apache.openjpa.persistence.annotations.TestJoinedInheritance;
+import org.apache.openjpa.persistence.annotations.TestManyToMany;
+import org.apache.openjpa.persistence.annotations.TestMapKey;
+import org.apache.openjpa.persistence.annotations.TestMappedSuperClass;
+import org.apache.openjpa.persistence.annotations.TestOneToOne;
+import org.apache.openjpa.persistence.annotations.TestPersistentCollection;
+import org.apache.openjpa.persistence.annotations.TestSerializedLobs;
+import org.apache.openjpa.persistence.annotations.TestTablePerClassInheritance;
+import org.apache.openjpa.persistence.datacache.TestDataCacheBehavesIdentical;
+import org.apache.openjpa.persistence.datacache.TestQueryResultSize;
+import org.apache.openjpa.persistence.detach.TestDetachNoCascade;
+import org.apache.openjpa.persistence.detachment.
+ TestGetReferenceAndImplicitDetachment;
+import org.apache.openjpa.persistence.enhance.identity.
+ TestMultipleLevelDerivedIdentity;
+import org.apache.openjpa.persistence.enhance.identity.
+ TestMultipleLevelDerivedIdentity1;
+import org.apache.openjpa.persistence.identity.TestFloatingPointIds;
+import org.apache.openjpa.persistence.identity.TestGenerationType;
+import org.apache.openjpa.persistence.identity.TestSQLBigDecimalId;
+import org.apache.openjpa.persistence.identity.TestSQLBigIntegerId;
+import org.apache.openjpa.persistence.identity.TestSQLDateId;
+import org.apache.openjpa.persistence.jdbc.annotations.TestEJBEmbedded;
+import org.apache.openjpa.persistence.jdbc.annotations.TestEmbeddableSuperclass;
+import org.apache.openjpa.persistence.jdbc.annotations.TestOneToMany;
+import org.apache.openjpa.persistence.jdbc.annotations.TestVersion;
+import org.apache.openjpa.persistence.jdbc.mapping.TestPrecisionMapping;
+import org.apache.openjpa.persistence.jdbc.maps.m2mmapex2.TestMany2ManyMapEx2;
+import org.apache.openjpa.persistence.jdbc.maps.m2mmapex6.TestMany2ManyMapEx6;
+import org.apache.openjpa.persistence.jpql.clauses.TestEJBClauses;
+import org.apache.openjpa.persistence.jpql.clauses.TestEJBDeleteUpdateImpl;
+import org.apache.openjpa.persistence.jpql.expressions.TestEntityTypeExpression;
+import org.apache.openjpa.persistence.kernel.TestExtents;
+import org.apache.openjpa.persistence.kernel.TestProxies2;
+import org.apache.openjpa.persistence.kernel.TestSavepoints;
+import org.apache.openjpa.persistence.kernel.TestStateManagerImplData;
+import org.apache.openjpa.persistence.kernel.TestStoreBlob;
+import org.apache.openjpa.persistence.lockmgr.TestMixedLockManagerLockBasic;
+import org.apache.openjpa.persistence.lockmgr.
+ TestMixedLockManagerLockPermutation;
+import org.apache.openjpa.persistence.meta.TestMetamodel;
+import org.apache.openjpa.persistence.query.TestComplexQueries;
+import org.apache.openjpa.persistence.query.TestNamedQueries;
+import org.apache.openjpa.persistence.query.TestQueryResults;
+import org.apache.openjpa.persistence.relations.
+ TestBulkUpdatesAndEmbeddedFields;
+import org.apache.openjpa.persistence.relations.
+ TestCascadingOneManyWithForeignKey;
+import org.apache.openjpa.persistence.relations.TestChainEntities;
+import org.apache.openjpa.persistence.relations.TestEagerBidiSQL;
+import org.apache.openjpa.persistence.relations.TestHandlerCollections;
+import org.apache.openjpa.persistence.relations.TestHandlerToHandlerMaps;
+import org.apache.openjpa.persistence.relations.TestHandlerToRelationMaps;
+import org.apache.openjpa.persistence.relations.TestIdOrderedOneMany;
+import org.apache.openjpa.persistence.relations.TestInverseEagerSQL;
+import org.apache.openjpa.persistence.relations.TestLRS;
+import org.apache.openjpa.persistence.relations.TestLazyManyToOne;
+import org.apache.openjpa.persistence.relations.TestManyEagerSQL;
+import org.apache.openjpa.persistence.relations.TestManyOneAsId;
+import org.apache.openjpa.persistence.relations.TestMapCollectionToBlob;
+import org.apache.openjpa.persistence.relations.
+ TestMultipleSameTypedEmbeddedWithEagerRelations;
+import org.apache.openjpa.persistence.relations.TestOneOneNulls;
+import org.apache.openjpa.persistence.relations.
+ TestRelationFieldAsPrimaryKeyAndForeignKey;
+import org.apache.openjpa.persistence.relations.TestRelationToHandlerMaps;
+import org.apache.openjpa.persistence.relations.TestRelationToRelationMaps;
+import org.apache.openjpa.persistence.relations.TestTargetedIFaceRelations;
+import org.apache.openjpa.persistence.simple.TestBasicAnnotation;
+import org.apache.openjpa.persistence.simple.TestCaseInsensitiveKeywordsInJPQL;
+import org.apache.openjpa.persistence.simple.TestEntityManagerClear;
+import org.apache.openjpa.persistence.simple.TestEntityManagerFactory;
+import org.apache.openjpa.persistence.simple.TestEntityManagerMerge;
+import org.apache.openjpa.persistence.simple.
+ TestEntityManagerMethodsThrowAfterClose;
+import org.apache.openjpa.persistence.simple.TestFlushBeforeDetach;
+import org.apache.openjpa.persistence.simple.TestJoin;
+import org.apache.openjpa.persistence.simple.TestPersistence;
+import org.apache.openjpa.persistence.simple.TestPropertiesMethods;
+import org.apache.openjpa.persistence.simple.TestRefresh;
+import org.apache.openjpa.persistence.simple.TestSerializedFactory;
+import org.apache.openjpa.persistence.simple.
+ TestTableNamesDefaultToEntityNames;
+import org.apache.openjpa.persistence.spring.TestLibService;
+import org.apache.openjpa.persistence.xml.TestSimpleXmlEntity;
+import org.apache.openjpa.persistence.xml.TestXmlOverrideEntity;
+
+public class DynamicEnhancementSuite extends TestCase {
+ static {
+ Persistence.createEntityManagerFactory("test", System.getProperties());
+ }
+
+ public static Test suite() throws Exception {
+ TestSuite suite = new TestSuite();
+
+ // Setting the property -DdynamicTest allows you to run a single test
+ // with the dynamic enhaner.
+ String test = System.getProperty("dynamicTest");
+ if (test != null) {
+ suite.addTestSuite(Class.forName(test));
+ } else {
+
+ // Subclassing failing tests
+ suite.addTestSuite(TestComplexQueries.class);
+ suite.addTestSuite(TestNamedQueries.class);
+ suite.addTestSuite(TestQueryResults.class);
+ suite.addTestSuite(TestMetamodel.class);
+ suite.addTestSuite(TestLibService.class);
+ suite.addTestSuite(TestOneOneNulls.class);
+ suite.addTestSuite(TestProxies2.class);
+ suite.addTestSuite(TestStoreBlob.class);
+ suite.addTestSuite(TestEntityTypeExpression.class);
+ suite.addTestSuite(TestSimpleXmlEntity.class);
+ suite.addTestSuite(TestDataCacheBehavesIdentical.class);
+ suite.addTestSuite(TestQueryResultSize.class);
+ suite.addTestSuite(TestEJBClauses.class);
+ suite.addTestSuite(TestEJBDeleteUpdateImpl.class);
+ suite.addTestSuite(TestOneToMany.class);
+ suite.addTestSuite(TestOneToOne.class);
+ suite.addTestSuite(TestGetReferenceAndImplicitDetachment.class);
+ suite.addTestSuite(TestMultipleLevelDerivedIdentity.class);
+ suite.addTestSuite(TestMultipleLevelDerivedIdentity1.class);
+ suite.addTestSuite(TestEJBEmbedded.class);
+ suite.addTestSuite(TestEmbeddableSuperclass.class);
+ suite.addTestSuite(TestFlatInheritance.class);
+ suite.addTestSuite(TestVersion.class);
+ suite.addTestSuite(TestMany2ManyMapEx2.class);
+ suite.addTestSuite(TestMany2ManyMapEx6.class);
+ suite.addTestSuite(TestOneOneNulls.class);
+ suite.addTestSuite(TestTargetedIFaceRelations.class);
+ suite.addTestSuite(TestExtents.class);
+ suite.addTestSuite(TestProxies2.class);
+ suite.addTestSuite(TestSavepoints.class);
+ suite.addTestSuite(TestStateManagerImplData.class);
+ suite.addTestSuite(TestStoreBlob.class);
+ suite.addTestSuite(TestEntityTypeExpression.class);
+ suite.addTestSuite(TestSimpleXmlEntity.class);
+ suite.addTestSuite(TestXmlOverrideEntity.class);
+ suite.addTestSuite(TestDataCacheBehavesIdentical.class);
+ suite.addTestSuite(TestQueryResultSize.class);
+ suite.addTestSuite(TestQueryResultSize.class);
+ suite.addTestSuite(TestDetachNoCascade.class);
+ suite.addTestSuite(TestMixedLockManagerLockBasic.class);
+ suite.addTestSuite(TestMixedLockManagerLockPermutation.class);
+ // end Subclassing failing tests
+
+ // org.apache.openjpa.persistence.enhance
+ suite.addTestSuite(TestMultipleLevelDerivedIdentity.class);
+ suite.addTestSuite(TestClone.class);
+
+ // excluded via pom
+ // suite.addTestSuite(TestDynamicStorageGenerator.class);
+ // suite.addTestSuite(TestNoNoArgs.class);
+ // suite.addTestSuite(TestSubclassedBehavior.class);
+
+ // org.apache.openjpa.persistence.relations
+ suite.addTestSuite(TestBulkUpdatesAndEmbeddedFields.class);
+ suite.addTestSuite(TestCascadingOneManyWithForeignKey.class);
+ suite.addTestSuite(TestChainEntities.class);
+ suite.addTestSuite(TestEagerBidiSQL.class);
+ suite.addTestSuite(TestHandlerCollections.class);
+ suite.addTestSuite(TestHandlerToHandlerMaps.class);
+ suite.addTestSuite(TestHandlerToRelationMaps.class);
+ suite.addTestSuite(TestIdOrderedOneMany.class);
+ suite.addTestSuite(TestInverseEagerSQL.class);
+ suite.addTestSuite(TestLazyManyToOne.class);
+ suite.addTestSuite(TestLRS.class);
+ suite.addTestSuite(TestManyEagerSQL.class);
+ suite.addTestSuite(TestManyOneAsId.class);
+ suite.addTestSuite(TestMapCollectionToBlob.class);
+ suite.addTestSuite(
+ TestMultipleSameTypedEmbeddedWithEagerRelations.class);
+ suite.addTestSuite(TestOneOneNulls.class);
+ suite
+ .addTestSuite(TestRelationFieldAsPrimaryKeyAndForeignKey.class);
+ suite.addTestSuite(TestRelationToHandlerMaps.class);
+ suite.addTestSuite(TestRelationToRelationMaps.class);
+ suite.addTestSuite(TestTargetedIFaceRelations.class);
+ // org.apache.openjpa.persistence.simple
+ suite.addTestSuite(TestBasicAnnotation.class);
+ suite.addTestSuite(TestCaseInsensitiveKeywordsInJPQL.class);
+ suite.addTestSuite(TestEntityManagerClear.class);
+ suite.addTestSuite(TestEntityManagerFactory.class);
+ suite.addTestSuite(TestEntityManagerMerge.class);
+ suite.addTestSuite(TestEntityManagerMethodsThrowAfterClose.class);
+ suite.addTestSuite(TestFlushBeforeDetach.class);
+ suite.addTestSuite(TestJoin.class);
+ // TODO -- figure out why this test fails.
+ // suite.addTestSuite(TestMissingMetaData.class);
+ suite.addTestSuite(TestPersistence.class);
+ suite.addTestSuite(TestPropertiesMethods.class);
+ suite.addTestSuite(TestRefresh.class);
+ suite.addTestSuite(TestSerializedFactory.class);
+ suite.addTestSuite(TestTableNamesDefaultToEntityNames.class);
+
+ // org.apache.openjpa.persistence.jdbc.mapping
+ // excluded via pom
+ // suite.addTestSuite(TestCompositeIdTraversalInSQLMapping.class);
+ // suite.addTestSuite(TestNativeQueries.class);
+ suite.addTestSuite(TestPrecisionMapping.class);
+
+ // org.apache.openjpa.persistence.identity
+ suite.addTestSuite(TestFloatingPointIds.class);
+ suite.addTestSuite(TestGenerationType.class);
+ suite.addTestSuite(TestSQLBigDecimalId.class);
+ suite.addTestSuite(TestSQLBigIntegerId.class);
+ suite.addTestSuite(TestSQLDateId.class);
+
+ // org.apache.openjpa.persistence.annotations
+ suite.addTestSuite(TestAnnotationBasics.class);
+ suite.addTestSuite(TestEmbeddableSuperclass.class);
+ suite.addTestSuite(TestEmbeddedId.class);
+ suite.addTestSuite(TestEnumerated.class);
+ suite.addTestSuite(TestFlatInheritance.class);
+ suite.addTestSuite(TestGenerators.class);
+ suite.addTestSuite(TestJoinedInheritance.class);
+ suite.addTestSuite(TestManyToMany.class);
+ suite.addTestSuite(TestMapKey.class);
+ suite.addTestSuite(TestMappedSuperClass.class);
+ suite.addTestSuite(TestOneToMany.class);
+ suite.addTestSuite(TestOneToOne.class);
+ suite.addTestSuite(TestPersistentCollection.class);
+ suite.addTestSuite(TestSerializedLobs.class);
+ suite.addTestSuite(TestTablePerClassInheritance.class);
+
+ // excluded via pom
+ // suite.addTestSuite(TestPropertyAccess.class);
+ // suite.addTestSuite(TestVersion.class);
+ // suite.addTestSuite(TestAdvAnnot.class);
+ // suite.addTestSuite(TestDDCallbackMethods.class);
+ // suite.addTestSuite(TestEJBEmbedded.class);
+ // suite.addTestSuite(TestEntityListenerAnnot.class);
+ // suite.addTestSuite(TestEntityOrderBy.class);
+ }
+ return suite;
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/DynamicEnhancementSuite.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestGenerators.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestGenerators.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestGenerators.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestGenerators.java Fri May 29 20:06:29 2009
@@ -21,8 +21,10 @@
import javax.persistence.EntityManager;
import javax.persistence.Query;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.enhance.ClassRedefiner;
import org.apache.openjpa.enhance.PersistenceCapable;
+import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
@@ -31,15 +33,16 @@
* @author Steve Kim
*/
public class TestGenerators extends SingleEMFTestCase {
-
+ Log _log;
public void setUp()
throws Exception {
setUp(Generator.class, CLEAR_TABLES);
+ _log = emf.getConfiguration().getLog(OpenJPAConfiguration.LOG_RUNTIME);
}
public void testGet() {
if (!PersistenceCapable.class.isAssignableFrom(Generator.class)
- && !ClassRedefiner.canRedefineClasses())
+ && !ClassRedefiner.canRedefineClasses(_log))
fail("This test requires a higher level of enhancement than"
+ " is available in the current environment.");
Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProviderImpl.java Fri May 29 20:06:29 2009
@@ -32,12 +32,12 @@
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
import org.apache.openjpa.enhance.PCClassFileTransformer;
+import org.apache.openjpa.enhance.PCEnhancerAgent;
import org.apache.openjpa.kernel.Bootstrap;
import org.apache.openjpa.kernel.BrokerFactory;
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.lib.conf.ConfigurationProvider;
import org.apache.openjpa.lib.conf.Configurations;
-import org.apache.openjpa.lib.conf.ProductDerivations;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.MetaDataModes;
@@ -61,6 +61,7 @@
private static final Localizer _loc = Localizer.forPackage(
PersistenceProviderImpl.class);
+ private static final String _name = PersistenceProviderImpl.class.getName();
private Log _log;
/**
* Loads the entity manager specified by <code>name</code>, applying
@@ -82,11 +83,12 @@
return null;
BrokerFactory factory = getBrokerFactory(cp, poolValue, null);
- _log = factory.getConfiguration()
- .getLog(OpenJPAConfiguration.LOG_RUNTIME);
+ OpenJPAConfiguration conf = factory.getConfiguration();
+ _log = conf.getLog(OpenJPAConfiguration.LOG_RUNTIME);
if(pd.checkPuNameCollisions(_log,name)==true){
;//return null;
}
+ loadAgent(_log, conf);
return JPAFacadeHelper.toEntityManagerFactory(factory);
} catch (Exception e) {
throw PersistenceExceptions.toPersistenceException(e);
@@ -233,4 +235,15 @@
throw new UnsupportedOperationException(
"JPA 2.0 - Method not yet implemented");
}
+ /**
+ * This private worker method will attempt load the PCEnhancerAgent.
+ */
+ private void loadAgent(Log log, OpenJPAConfiguration conf) {
+ if (conf.getDynamicEnhancementAgent() == true) {
+ boolean res = PCEnhancerAgent.loadDynamicAgent(log);
+ if(_log.isInfoEnabled() && res == true ){
+ _log.info(_loc.get("dynamic-agent"));
+ }
+ }
+ }
}
Modified: openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties (original)
+++ openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties Fri May 29 20:06:29 2009
@@ -180,16 +180,19 @@
invalid_entity_argument: Object being locked must be an valid and not detached \
entity.
dup-pu: The persistence unit "{0}" was found multiple times in the following \
- resources "{1}", but persistence unit names should be unique. The first \
- persistence unit matching the provided name in "{2}" is being used.
+ resources "{1}", but persistence unit names should be unique. The first \
+ persistence unit matching the provided name in "{2}" is being used.
bad-lock-level: Invalid lock mode/level. Valid values are \
"none"(0), "read"(10), "optimistic"(15), "write"(20), \
"optimistic-force-increment"(25), \
"pessimistic-read"(30), "pessimistic-write"(40) or \
"pessimistic-force-increment"(50). Specified value: {0}.
access-invalid: "{0}" is not a valid access style. Valid access styles are \
- "PROPERTY" and "FIELD".
+ "PROPERTY" and "FIELD".
getter-unmatched: Getter method "{0}" has no matching setter method.
invalid-orderBy: This is not a valid OrderBy annotation. The property or \
field_name must be specified in the orederBy item of the orderBy list \
- for "{0}".
\ No newline at end of file
+ for "{0}".
+dynamic-agent: OpenJPA dynamically loaded the class enhancer. Any classes \
+ that were not enhanced at build time will be enhanced when the are \
+ loaded by the JVM
Modified: openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml (original)
+++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml Fri May 29 20:06:29 2009
@@ -2958,6 +2958,36 @@
<xref linkend="ref_guide_pc_enhance_unenhanced_types"/>
</para>
</section>
+ <section id="openjpa.DynamicEnhancementAgent">
+ <title>openjpa.DynamicEnhancementAgent</title>
+ <para>
+ <emphasis role="bold">Property name: </emphasis>
+ <literal>openjpa.DynamicEnhancementAgent</literal>
+ </para>
+ <para>
+ <emphasis role="bold">Configuration API: </emphasis>
+ <ulink url="../javadoc/org/apache/openjpa/conf/OpenJPAConfiguration.html#getDynamicEnhancementAgent()">org.apache.openjpa.conf.OpenJPAConfiguration.getDynamicEnhancementAgent</ulink>
+ </para>
+ <para>
+ <emphasis role="bold">Resource adaptor config property:</emphasis>
+ DynamicEnhancementAgent
+ </para>
+ <para>
+ <emphasis role="bold">Default: </emphasis>
+ <literal>true</literal>
+
+ </para>
+ <para>
+ <emphasis role="bold">Description:</emphasis>
+ The DynamicEnhancementAgent property controls whether or not
+ OpenJPA will attempt to dynamically load the PCEnhancer
+ javaagent.
+ </para>
+ <para>
+ See the reference guide for more information
+ <xref linkend="ref_guide_pc_enhance_dynamic"/>
+ </para>
+ </section>
<section id="openjpa.SavepointManager">
<title>
openjpa.SavepointManager
Modified: openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml (original)
+++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_pc.xml Fri May 29 20:06:29 2009
@@ -380,6 +380,55 @@
</programlisting>
</example>
</section>
+<section id="ref_guide_pc_enhance_dynamic">
+ <title>
+ Enhancing Dynamically at Runtime
+ </title>
+ <para>
+ If a javaagent is not provided via the command line and
+ OpenJPA is running on the Sun 1.6 SDK (not the JRE), OpenJPA
+ will attempt to dynamically load the Enhancer that was
+ mentioned in the previous section. This support is
+ provided as an ease of use feature and it is not recommended
+ for use in a production system. Using this method of
+ enhancement has the following caveats:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ As stated previously, this is only supported on
+ the Sun 1.6 SDK.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The dynamic runtime enhancer is plugged into
+ the JVM during creation of the
+ EntityManagerFactory. Any Entity classes that
+ are loaded before the EntityManagerFactory is
+ created will not be enhanced.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The command line javaagent settings are not
+ configurable when using this method of
+ enhancement.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ When then dynamic enhancer is loaded, the following
+ informational message is logged:
+<programlisting>
+[java] jpa.enhancement INFO [main] openjpa.Runtime - OpenJPA dynamically loaded the class enhancer. Any classes that were not enhanced at build time will be enhanced as they are loaded by the JVM.
+</programlisting>
+ </para>
+ <para>
+ Setting the property openjpa.DynamicEnhancementAgent to false
+ will disable this function.
+ </para>
+</section>
<section id="ref_guide_pc_enhance_unenhanced_types">
<title>
Omitting the OpenJPA enhancer
Modified: openjpa/trunk/openjpa/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa/pom.xml?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/openjpa/pom.xml (original)
+++ openjpa/trunk/openjpa/pom.xml Fri May 29 20:06:29 2009
@@ -87,7 +87,7 @@
</plugin>
<!--
- create enhancer pre-main attribute
+ create enhancer pre-main and agent-main attributes
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -103,6 +103,11 @@
org.apache.openjpa.enhance.PCEnhancerAgent
</Premain-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
+ <Agent-Class>
+ org.apache.openjpa.enhance.InstrumentationFactory
+ </Agent-Class>
+ <Can-Redefine-Classes>true</Can-Redefine-Classes>
+ <Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
Modified: openjpa/trunk/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/pom.xml?rev=780086&r1=780085&r2=780086&view=diff
==============================================================================
--- openjpa/trunk/pom.xml (original)
+++ openjpa/trunk/pom.xml Fri May 29 20:06:29 2009
@@ -403,6 +403,31 @@
<surefire.jvm.args>-Djava.security.manager -Djava.security.policy=${policy.file} ${test.env}</surefire.jvm.args>
</properties>
</profile>
+ <profile>
+ <id>test-dynamic-enhancer</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <properties>
+ <test.env>-Dtest.basedir=${basedir}/..</test.env>
+ <policy.file>${basedir}/../openjpa-persistence-jdbc/src/test/resources/j2.security.test.policy</policy.file>
+ <surefire.jvm.args>-Djava.security.manager -Djava.security.policy=${policy.file} ${test.env}</surefire.jvm.args>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <argLine>${test.jvm.arguments}</argLine>
+ <includes>
+ <include></include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
</profiles>