OPENJPA-952. Committing patch from Rick Curtis

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@780086 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Dick 2009-05-29 20:06:29 +00:00
parent 016d49b4c0
commit 2b942805f2
18 changed files with 849 additions and 120 deletions

View File

@ -1557,7 +1557,15 @@ public interface OpenJPAConfiguration
* @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.

View File

@ -28,6 +28,7 @@ import org.apache.openjpa.datacache.ConcurrentQueryCache;
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 @@ public class OpenJPAConfigurationImpl
new StoreFacadeTypeRegistry();
private BrokerFactoryEventManager _brokerFactoryEventManager =
new BrokerFactoryEventManager(this);
public BooleanValue dynamicEnhancementAgent;
/**
* Default constructor. Attempts to load global properties.
@ -572,6 +575,10 @@ public class OpenJPAConfigurationImpl
"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 class OpenJPAConfigurationImpl
public void setValidationFactory(Object factory) {
validationFactory.set(factory);
}
public boolean getDynamicEnhancementAgent() {
return dynamicEnhancementAgent.get();
}
public void setDynamicEnhancementAgent(boolean dynamic) {
dynamicEnhancementAgent.set(dynamic);
}
}

View File

@ -60,14 +60,15 @@ public class ClassRedefiner {
*/
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 @@ public class ClassRedefiner {
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 @@ public class ClassRedefiner {
* 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) {

View File

@ -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 @@ import org.apache.openjpa.lib.util.*;
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 @@ public class InstrumentationFactory {
_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,59 +84,30 @@ public class InstrumentationFactory {
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;
}
// 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;
}
/**
* 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");
file.deleteOnExit();
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(file));
zout.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
PrintWriter writer = new PrintWriter
(new OutputStreamWriter(zout));
writer.println("Agent-Class: "
+ InstrumentationFactory.class.getName());
writer.println("Can-Redefine-Classes: true");
writer.println("Can-Retransform-Classes: true");
writer.close();
return file.getAbsolutePath();
}
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()
/**
* The method that is called when a jar is added as an agent at runtime.
@ -120,4 +117,191 @@ public class InstrumentationFactory {
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.
*
* @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));
writer
.println("Agent-Class: " + InstrumentationFactory.class.getName());
writer.println("Can-Redefine-Classes: true");
writer.println("Can-Retransform-Classes: true");
writer.close();
return file.getAbsolutePath();
}
/**
* 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.
*/
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;
}
}

View File

@ -95,6 +95,21 @@ public class ManagedClassSubclasser {
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 @@ public class ManagedClassSubclasser {
return null;
}
boolean redefine = ClassRedefiner.canRedefineClasses();
boolean redefine = ClassRedefiner.canRedefineClasses(log);
if (redefine)
log.info(_loc.get("enhance-and-subclass-and-redef-start",
classes));

View File

@ -20,47 +20,109 @@ package org.apache.openjpa.enhance;
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[=&lt;options&gt;]</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[=&lt;options&gt;]</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 @@ public class PCEnhancerAgent {
} else {
InstrumentationFactory.setDynamicallyInstallAgent(false);
}
loadSuccessful = true;
}
private static void registerClassLoadEnhancer(Instrumentation inst,

View File

@ -206,3 +206,9 @@ most-derived-unrelated: Methods "{0}" and "{1}" are defined in types that do \
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.

View File

@ -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>

View File

@ -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.

View File

@ -26,11 +26,13 @@ import java.io.ByteArrayInputStream;
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 @@ import org.apache.openjpa.event.LifecycleEvent;
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 @@ public abstract class AbstractUnenhancedClassTest
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 abstract class AbstractUnenhancedClassTest
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 @@ public abstract class AbstractUnenhancedClassTest
// 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 @@ public abstract class AbstractUnenhancedClassTest
// 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()));

View File

@ -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;
}
}

View File

@ -21,8 +21,10 @@ package org.apache.openjpa.persistence.jdbc.annotations;
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 @@ import org.apache.openjpa.persistence.test.SingleEMFTestCase;
* @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.");

View File

@ -32,12 +32,12 @@ import org.apache.openjpa.conf.BrokerValue;
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 @@ public class PersistenceProviderImpl
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 @@ public class PersistenceProviderImpl
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 @@ public class PersistenceProviderImpl
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"));
}
}
}
}

View File

@ -180,16 +180,19 @@ unwrap-query-invalid: Query can not be unwrapped to an instance of "{0}".
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}".
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

View File

@ -2958,6 +2958,36 @@ serious problems.
<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

View File

@ -380,6 +380,55 @@ java -javaagent:/home/dev/openjpa/lib/openjpa.jar=addDefaultConstructor=false co
</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

View File

@ -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>

25
pom.xml
View File

@ -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>