blob: fb6d07bbcb28657c1fdd9cf29f1c5bc0c890e050 [file] [log] [blame]
/**
*
* 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.openejb.core.cmp.jpa;
import junit.framework.TestCase;
import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
import org.apache.openejb.core.TempClassLoader;
import org.apache.openejb.javaagent.Agent;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.persistence.PersistenceClassLoaderHandler;
import org.apache.openejb.persistence.PersistenceUnitInfoImpl;
import org.apache.openejb.resource.jdbc.dbcp.BasicDataSource;
import org.apache.openejb.resource.jdbc.dbcp.BasicManagedDataSource;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Properties;
public class UnenhancedTest extends TestCase {
private static final String PERSISTENCE_PROVIDER = "org.apache.openjpa.persistence.PersistenceProviderImpl";
private GeronimoTransactionManager transactionManager;
private DataSource jtaDs;
private DataSource nonJtaDs;
private EntityManagerFactory entityManagerFactory;
private boolean enhance;
public void setUp() throws Exception {
super.setUp();
// setup tx mgr
transactionManager = new GeronimoTransactionManager();
SystemInstance.get().setComponent(TransactionSynchronizationRegistry.class, transactionManager);
// Put tx mgr into SystemInstance so OpenJPA can find it
SystemInstance.get().setComponent(TransactionManager.class, transactionManager);
// init databases
jtaDs = createJtaDataSource(transactionManager);
nonJtaDs = createNonJtaDataSource();
}
public void tearDown() throws Exception {
if (entityManagerFactory != null && entityManagerFactory.isOpen()) {
entityManagerFactory.close();
}
if (nonJtaDs != null) {
Connection connection = nonJtaDs.getConnection();
Statement statement = connection.createStatement();
statement.execute("SHUTDOWN");
close(statement);
close(connection);
}
nonJtaDs = null;
jtaDs = null;
// diable any enhancers we added
enhance = false;
super.tearDown();
}
public void testEnhancedComplexIdJta() throws Exception {
runTest("complexId", PersistenceUnitTransactionType.JTA, true);
}
public void testEnhancedComplexIdResourceLocal() throws Exception {
runTest("complexId", PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
}
public void testUnenhancedComplexIdJta() throws Exception {
runTest("complexId", PersistenceUnitTransactionType.JTA, false);
}
public void testUnenhancedComplexIdResourceLocal() throws Exception {
runTest("complexId", PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
}
public void testEnhancedComplexIdSubclassJta() throws Exception {
runTest("complexIdSubclass", PersistenceUnitTransactionType.JTA, true);
}
public void testEnhancedComplexIdSubclassResourceLocal() throws Exception {
runTest("complexIdSubclass", PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
}
// todo OpenJPA
public void XtestUnenhancedComplexIdSubclassJta() throws Exception {
runTest("complexIdSubclass", PersistenceUnitTransactionType.JTA, false);
}
// todo OpenJPA
public void XtestUnenhancedComplexIdSubclassResourceLocal() throws Exception {
runTest("complexIdSubclass", PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
}
public void testEnhancedGeneratedIdJta() throws Exception {
runTest("generatedId", PersistenceUnitTransactionType.JTA, true);
}
public void testEnhancedGeneratedIdResourceLocal() throws Exception {
runTest("generatedId", PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
}
// todo OpenJPA
public void XtestUnenhancedGeneratedIdJta() throws Exception {
runTest("generatedId", PersistenceUnitTransactionType.JTA, false);
}
// todo OpenJPA
public void XtestUnenhancedGeneratedIdResourceLocal() throws Exception {
runTest("generatedId", PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
}
public void testEnhancedGeneratedIdSubclassJta() throws Exception {
runTest("generatedIdSubclass", PersistenceUnitTransactionType.JTA, true);
}
public void testEnhancedGeneratedIdSubclassResourceLocal() throws Exception {
runTest("generatedIdSubclass", PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
}
// todo OpenJPA
public void XtestUnenhancedGeneratedIdSubclassJta() throws Exception {
runTest("generatedIdSubclass", PersistenceUnitTransactionType.JTA, false);
}
// todo OpenJPA
public void XtestUnenhancedGeneratedIdSubclassResourceLocal() throws Exception {
runTest("generatedIdSubclass", PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
}
public void testEnhancedCollectionJta() throws Exception {
runTest("collection", PersistenceUnitTransactionType.JTA, true);
}
public void testEnhancedCollectionResourceLocal() throws Exception {
runTest("collection", PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
}
// todo OpenJPA
public void XtestUnenhancedCollectionJta() throws Exception {
runTest("collection", PersistenceUnitTransactionType.JTA, false);
}
// todo OpenJPA
public void XtestUnenhancedCollectionResourceLocal() throws Exception {
runTest("collection", PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
}
private void runTest(String methodName, PersistenceUnitTransactionType transactionType, boolean enhance) throws Exception {
this.enhance = enhance;
ClassLoader loader = new FilteredChildFirstClassLoader(getClass().getClassLoader(), "org.apache.openejb.core.cmp.jpa");
PersistenceClassLoaderHandler persistenceClassLoaderHandler = new PersistenceClassLoaderHandler() {
public void addTransformer(String unitId, ClassLoader classLoader, ClassFileTransformer classFileTransformer) {
Instrumentation instrumentation = Agent.getInstrumentation();
if (instrumentation != null) {
instrumentation.addTransformer(new ControllableTransformer(classFileTransformer));
}
}
public void destroy(String unitId) {
}
public ClassLoader getNewTempClassLoader(ClassLoader classLoader) {
return new TempClassLoader(classLoader);
}
};
PersistenceUnitInfoImpl unitInfo = new PersistenceUnitInfoImpl(persistenceClassLoaderHandler);
unitInfo.setPersistenceUnitName("CMP");
unitInfo.setPersistenceProviderClassName(PERSISTENCE_PROVIDER);
unitInfo.setClassLoader(loader);
unitInfo.setExcludeUnlistedClasses(false);
unitInfo.setJtaDataSource(jtaDs);
unitInfo.setNonJtaDataSource(nonJtaDs);
unitInfo.addManagedClassName("org.apache.openejb.core.cmp.jpa.ComplexSuperclass");
unitInfo.addManagedClassName("org.apache.openejb.core.cmp.jpa.ComplexSubclass");
unitInfo.addManagedClassName("org.apache.openejb.core.cmp.jpa.ComplexStandalone");
unitInfo.addManagedClassName("org.apache.openejb.core.cmp.jpa.GeneratedStandalone");
unitInfo.addManagedClassName("org.apache.openejb.core.cmp.jpa.GeneratedSuperclass");
unitInfo.addManagedClassName("org.apache.openejb.core.cmp.jpa.GeneratedSubclass");
unitInfo.addManagedClassName("org.apache.openejb.core.cmp.jpa.OneStandalone");
unitInfo.addManagedClassName("org.apache.openejb.core.cmp.jpa.ManyStandalone");
// Handle Properties
Properties properties = new Properties();
properties.setProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema(SchemaAction='add,deleteTableContents',ForeignKeys=true)");
properties.setProperty("openjpa.RuntimeUnenhancedClasses", "supported");
properties.setProperty("openjpa.Log", "DefaultLevel=INFO");
unitInfo.setProperties(properties);
unitInfo.setTransactionType(transactionType);
unitInfo.getManagedClassNames().add("org.apache.openejb.core.cmp.jpa.Employee");
PersistenceProvider persistenceProvider = (PersistenceProvider) getClass().getClassLoader().loadClass(PERSISTENCE_PROVIDER).newInstance();
entityManagerFactory = persistenceProvider.createContainerEntityManagerFactory(unitInfo, new HashMap());
// create the test object (via reflection)
Object testObject = loader.loadClass("org.apache.openejb.core.cmp.jpa.UnenhancedUnits").newInstance();
set(testObject, "TransactionManager", TransactionManager.class, transactionManager);
set(testObject, "EntityManagerFactory", EntityManagerFactory.class, entityManagerFactory);
// invoke the test (via reflection)
Thread.currentThread().setContextClassLoader(loader);
invoke(testObject, "setUp");
try {
invoke(testObject, methodName);
} finally {
invoke(testObject, "tearDown");
}
}
private DataSource createJtaDataSource(TransactionManager transactionManager) throws Exception {
BasicManagedDataSource ds = new BasicManagedDataSource(getClass().getName() + ".createJtaDs");
ds.setTransactionManager(transactionManager);
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl("jdbc:hsqldb:mem:JpaTest");
ds.setUsername("sa");
ds.setPassword("");
ds.setMaxActive(100);
ds.setMaxWait(10000);
ds.setTestOnBorrow(true);
return ds;
}
private DataSource createNonJtaDataSource() throws Exception {
BasicDataSource ds = new BasicDataSource(getClass().getName() + ".createNonJtaDs");
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl("jdbc:hsqldb:mem:JpaTest");
ds.setUsername("sa");
ds.setPassword("");
ds.setMaxActive(100);
ds.setMaxWait(10000);
ds.setTestOnBorrow(true);
return ds;
}
private static void set(Object instance, String parameterName, Class type, Object value) throws Exception {
try {
instance.getClass().getMethod("set" + parameterName, type).invoke(instance, value);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof Exception) {
throw (Exception) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
} else {
throw e;
}
}
}
private static void invoke(Object instance, String methodName) throws Exception {
try {
instance.getClass().getMethod(methodName).invoke(instance);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof Exception) {
throw (Exception) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
} else {
throw e;
}
}
}
private static void close(Statement statement) {
if (statement == null) {
return;
}
try {
statement.close();
} catch (SQLException e) {
}
}
private static void close(Connection connection) {
if (connection == null) {
return;
}
try {
connection.close();
} catch (SQLException e) {
}
}
private class ControllableTransformer implements ClassFileTransformer {
private final ClassFileTransformer transformer;
public ControllableTransformer(ClassFileTransformer transformer) {
this.transformer = transformer;
}
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (enhance) {
return transformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
} else {
return null;
}
}
}
public class FilteredChildFirstClassLoader extends URLClassLoader {
protected String packagePrefix;
public FilteredChildFirstClassLoader(ClassLoader parent, String packagePrefix) {
super(new URL[0], parent);
this.packagePrefix = packagePrefix;
}
public Class loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
// see if we've already loaded it
Class c = findLoadedClass(name);
if (c != null) {
return c;
}
if (!name.startsWith(packagePrefix)) {
return Class.forName(name, resolve, getParent());
}
String resourceName = name.replace('.', '/') + ".class";
InputStream in = getResourceAsStream(resourceName);
if (in == null) {
throw new ClassNotFoundException(name);
}
// 80% of class files are smaller then 6k
ByteArrayOutputStream bout = new ByteArrayOutputStream(8 * 1024);
// copy the input stream into a byte array
byte[] bytes = new byte[0];
try {
byte[] buf = new byte[4 * 1024];
for (int count = -1; (count = in.read(buf)) >= 0;) {
bout.write(buf, 0, count);
}
bytes = bout.toByteArray();
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
// define the package
int packageEndIndex = name.lastIndexOf('.');
if (packageEndIndex != -1) {
String packageName = name.substring(0, packageEndIndex);
if (getPackage(packageName) == null) {
definePackage(packageName, null, null, null, null, null, null, null);
}
}
// define the class
try {
return defineClass(name, bytes, 0, bytes.length);
} catch (SecurityException e) {
// possible prohibited package: defer to the parent
return super.loadClass(name, resolve);
}
}
}
}