001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.core.cmp.jpa;
018:
019: import junit.framework.TestCase;
020: import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
021: import org.apache.openejb.core.TempClassLoader;
022: import org.apache.openejb.javaagent.Agent;
023: import org.apache.openejb.loader.SystemInstance;
024: import org.apache.openejb.persistence.PersistenceClassLoaderHandler;
025: import org.apache.openejb.persistence.PersistenceUnitInfoImpl;
026: import org.apache.openejb.resource.jdbc.BasicDataSource;
027: import org.apache.openejb.resource.jdbc.BasicManagedDataSource;
028:
029: import javax.persistence.EntityManagerFactory;
030: import javax.persistence.spi.PersistenceProvider;
031: import javax.persistence.spi.PersistenceUnitTransactionType;
032: import javax.sql.DataSource;
033: import javax.transaction.TransactionManager;
034: import javax.transaction.TransactionSynchronizationRegistry;
035: import java.io.ByteArrayOutputStream;
036: import java.io.IOException;
037: import java.io.InputStream;
038: import java.lang.instrument.ClassFileTransformer;
039: import java.lang.instrument.IllegalClassFormatException;
040: import java.lang.instrument.Instrumentation;
041: import java.lang.reflect.InvocationTargetException;
042: import java.net.URL;
043: import java.net.URLClassLoader;
044: import java.security.ProtectionDomain;
045: import java.sql.Connection;
046: import java.sql.SQLException;
047: import java.sql.Statement;
048: import java.util.HashMap;
049: import java.util.Properties;
050:
051: public class UnenhancedTest extends TestCase {
052: private static final String PERSISTENCE_PROVIDER = "org.apache.openjpa.persistence.PersistenceProviderImpl";
053:
054: private GeronimoTransactionManager transactionManager;
055: private DataSource jtaDs;
056: private DataSource nonJtaDs;
057: private EntityManagerFactory entityManagerFactory;
058:
059: private boolean enhance;
060:
061: public void setUp() throws Exception {
062: super .setUp();
063:
064: // setup tx mgr
065: transactionManager = new GeronimoTransactionManager();
066: SystemInstance.get().setComponent(
067: TransactionSynchronizationRegistry.class,
068: transactionManager);
069:
070: // Put tx mgr into SystemInstance so OpenJPA can find it
071: SystemInstance.get().setComponent(TransactionManager.class,
072: transactionManager);
073:
074: // init databases
075: jtaDs = createJtaDataSource(transactionManager);
076: nonJtaDs = createNonJtaDataSource();
077: }
078:
079: public void tearDown() throws Exception {
080: if (entityManagerFactory != null
081: && entityManagerFactory.isOpen()) {
082: entityManagerFactory.close();
083: }
084:
085: if (nonJtaDs != null) {
086: Connection connection = nonJtaDs.getConnection();
087: Statement statement = connection.createStatement();
088: statement.execute("SHUTDOWN");
089: close(statement);
090: close(connection);
091: }
092:
093: nonJtaDs = null;
094: jtaDs = null;
095:
096: // diable any enhancers we added
097: enhance = false;
098:
099: super .tearDown();
100: }
101:
102: public void testEnhancedComplexIdJta() throws Exception {
103: runTest("complexId", PersistenceUnitTransactionType.JTA, true);
104: }
105:
106: public void testEnhancedComplexIdResourceLocal() throws Exception {
107: runTest("complexId",
108: PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
109: }
110:
111: public void testUnenhancedComplexIdJta() throws Exception {
112: runTest("complexId", PersistenceUnitTransactionType.JTA, false);
113: }
114:
115: public void testUnenhancedComplexIdResourceLocal() throws Exception {
116: runTest("complexId",
117: PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
118: }
119:
120: public void testEnhancedComplexIdSubclassJta() throws Exception {
121: runTest("complexIdSubclass",
122: PersistenceUnitTransactionType.JTA, true);
123: }
124:
125: public void testEnhancedComplexIdSubclassResourceLocal()
126: throws Exception {
127: runTest("complexIdSubclass",
128: PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
129: }
130:
131: // todo OpenJPA
132: public void XtestUnenhancedComplexIdSubclassJta() throws Exception {
133: runTest("complexIdSubclass",
134: PersistenceUnitTransactionType.JTA, false);
135: }
136:
137: // todo OpenJPA
138: public void XtestUnenhancedComplexIdSubclassResourceLocal()
139: throws Exception {
140: runTest("complexIdSubclass",
141: PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
142: }
143:
144: public void testEnhancedGeneratedIdJta() throws Exception {
145: runTest("generatedId", PersistenceUnitTransactionType.JTA, true);
146: }
147:
148: public void testEnhancedGeneratedIdResourceLocal() throws Exception {
149: runTest("generatedId",
150: PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
151: }
152:
153: // todo OpenJPA
154: public void XtestUnenhancedGeneratedIdJta() throws Exception {
155: runTest("generatedId", PersistenceUnitTransactionType.JTA,
156: false);
157: }
158:
159: // todo OpenJPA
160: public void XtestUnenhancedGeneratedIdResourceLocal()
161: throws Exception {
162: runTest("generatedId",
163: PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
164: }
165:
166: public void testEnhancedGeneratedIdSubclassJta() throws Exception {
167: runTest("generatedIdSubclass",
168: PersistenceUnitTransactionType.JTA, true);
169: }
170:
171: public void testEnhancedGeneratedIdSubclassResourceLocal()
172: throws Exception {
173: runTest("generatedIdSubclass",
174: PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
175: }
176:
177: // todo OpenJPA
178: public void XtestUnenhancedGeneratedIdSubclassJta()
179: throws Exception {
180: runTest("generatedIdSubclass",
181: PersistenceUnitTransactionType.JTA, false);
182: }
183:
184: // todo OpenJPA
185: public void XtestUnenhancedGeneratedIdSubclassResourceLocal()
186: throws Exception {
187: runTest("generatedIdSubclass",
188: PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
189: }
190:
191: public void testEnhancedCollectionJta() throws Exception {
192: runTest("collection", PersistenceUnitTransactionType.JTA, true);
193: }
194:
195: public void testEnhancedCollectionResourceLocal() throws Exception {
196: runTest("collection",
197: PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
198: }
199:
200: // todo OpenJPA
201: public void XtestUnenhancedCollectionJta() throws Exception {
202: runTest("collection", PersistenceUnitTransactionType.JTA, false);
203: }
204:
205: // todo OpenJPA
206: public void XtestUnenhancedCollectionResourceLocal()
207: throws Exception {
208: runTest("collection",
209: PersistenceUnitTransactionType.RESOURCE_LOCAL, false);
210: }
211:
212: private void runTest(String methodName,
213: PersistenceUnitTransactionType transactionType,
214: boolean enhance) throws Exception {
215: this .enhance = enhance;
216:
217: ClassLoader loader = new FilteredChildFirstClassLoader(
218: getClass().getClassLoader(),
219: "org.apache.openejb.core.cmp.jpa");
220:
221: PersistenceClassLoaderHandler persistenceClassLoaderHandler = new PersistenceClassLoaderHandler() {
222:
223: public void addTransformer(String unitId,
224: ClassLoader classLoader,
225: ClassFileTransformer classFileTransformer) {
226: Instrumentation instrumentation = Agent
227: .getInstrumentation();
228: if (instrumentation != null) {
229: instrumentation
230: .addTransformer(new ControllableTransformer(
231: classFileTransformer));
232: }
233: }
234:
235: public void destroy(String unitId) {
236: }
237:
238: public ClassLoader getNewTempClassLoader(
239: ClassLoader classLoader) {
240: return new TempClassLoader(classLoader);
241: }
242: };
243:
244: PersistenceUnitInfoImpl unitInfo = new PersistenceUnitInfoImpl(
245: persistenceClassLoaderHandler);
246: unitInfo.setPersistenceUnitName("CMP");
247: unitInfo.setPersistenceProviderClassName(PERSISTENCE_PROVIDER);
248: unitInfo.setClassLoader(loader);
249: unitInfo.setExcludeUnlistedClasses(false);
250: unitInfo.setJtaDataSource(jtaDs);
251: unitInfo.setNonJtaDataSource(nonJtaDs);
252: unitInfo
253: .addManagedClassName("org.apache.openejb.core.cmp.jpa.ComplexSuperclass");
254: unitInfo
255: .addManagedClassName("org.apache.openejb.core.cmp.jpa.ComplexSubclass");
256: unitInfo
257: .addManagedClassName("org.apache.openejb.core.cmp.jpa.ComplexStandalone");
258: unitInfo
259: .addManagedClassName("org.apache.openejb.core.cmp.jpa.GeneratedStandalone");
260: unitInfo
261: .addManagedClassName("org.apache.openejb.core.cmp.jpa.GeneratedSuperclass");
262: unitInfo
263: .addManagedClassName("org.apache.openejb.core.cmp.jpa.GeneratedSubclass");
264: unitInfo
265: .addManagedClassName("org.apache.openejb.core.cmp.jpa.OneStandalone");
266: unitInfo
267: .addManagedClassName("org.apache.openejb.core.cmp.jpa.ManyStandalone");
268:
269: // Handle Properties
270: Properties properties = new Properties();
271: properties
272: .setProperty("openjpa.jdbc.SynchronizeMappings",
273: "buildSchema(SchemaAction='add,deleteTableContents',ForeignKeys=true)");
274: properties.setProperty("openjpa.Log", "DefaultLevel=WARN");
275: unitInfo.setProperties(properties);
276:
277: unitInfo.setTransactionType(transactionType);
278:
279: unitInfo.getManagedClassNames().add(
280: "org.apache.openejb.core.cmp.jpa.Employee");
281:
282: PersistenceProvider persistenceProvider = (PersistenceProvider) getClass()
283: .getClassLoader().loadClass(PERSISTENCE_PROVIDER)
284: .newInstance();
285: entityManagerFactory = persistenceProvider
286: .createContainerEntityManagerFactory(unitInfo,
287: new HashMap());
288:
289: // create the test object (via reflection)
290: Object testObject = loader.loadClass(
291: "org.apache.openejb.core.cmp.jpa.UnenhancedUnits")
292: .newInstance();
293: set(testObject, "TransactionManager", TransactionManager.class,
294: transactionManager);
295: set(testObject, "EntityManagerFactory",
296: EntityManagerFactory.class, entityManagerFactory);
297:
298: // invoke the test (via reflection)
299: Thread.currentThread().setContextClassLoader(loader);
300: invoke(testObject, "setUp");
301: try {
302: invoke(testObject, methodName);
303: } finally {
304: invoke(testObject, "tearDown");
305: }
306: }
307:
308: private DataSource createJtaDataSource(
309: TransactionManager transactionManager) throws Exception {
310: BasicManagedDataSource ds = new BasicManagedDataSource();
311: ds.setTransactionManager(transactionManager);
312: ds.setDriverClassName("org.hsqldb.jdbcDriver");
313: ds.setUrl("jdbc:hsqldb:mem:JpaTest");
314: ds.setUsername("sa");
315: ds.setPassword("");
316: ds.setMaxActive(100);
317: ds.setMaxWait(10000);
318: ds.setTestOnBorrow(true);
319: return ds;
320: }
321:
322: private DataSource createNonJtaDataSource() throws Exception {
323: BasicDataSource ds = new BasicDataSource();
324: ds.setDriverClassName("org.hsqldb.jdbcDriver");
325: ds.setUrl("jdbc:hsqldb:mem:JpaTest");
326: ds.setUsername("sa");
327: ds.setPassword("");
328: ds.setMaxActive(100);
329: ds.setMaxWait(10000);
330: ds.setTestOnBorrow(true);
331: return ds;
332: }
333:
334: private static void set(Object instance, String parameterName,
335: Class type, Object value) throws Exception {
336: try {
337: instance.getClass().getMethod("set" + parameterName, type)
338: .invoke(instance, value);
339: } catch (InvocationTargetException e) {
340: Throwable cause = e.getCause();
341: if (cause instanceof Exception) {
342: throw (Exception) cause;
343: } else if (cause instanceof Error) {
344: throw (Error) cause;
345: } else {
346: throw e;
347: }
348: }
349: }
350:
351: private static void invoke(Object instance, String methodName)
352: throws Exception {
353: try {
354: instance.getClass().getMethod(methodName).invoke(instance);
355: } catch (InvocationTargetException e) {
356: Throwable cause = e.getCause();
357: if (cause instanceof Exception) {
358: throw (Exception) cause;
359: } else if (cause instanceof Error) {
360: throw (Error) cause;
361: } else {
362: throw e;
363: }
364: }
365: }
366:
367: private static void close(Statement statement) {
368: if (statement == null) {
369: return;
370: }
371: try {
372: statement.close();
373: } catch (SQLException e) {
374: }
375: }
376:
377: private static void close(Connection connection) {
378: if (connection == null) {
379: return;
380: }
381: try {
382: connection.close();
383: } catch (SQLException e) {
384: }
385: }
386:
387: private class ControllableTransformer implements
388: ClassFileTransformer {
389: private final ClassFileTransformer transformer;
390:
391: public ControllableTransformer(ClassFileTransformer transformer) {
392: this .transformer = transformer;
393: }
394:
395: public byte[] transform(ClassLoader loader, String className,
396: Class<?> classBeingRedefined,
397: ProtectionDomain protectionDomain,
398: byte[] classfileBuffer)
399: throws IllegalClassFormatException {
400: if (enhance) {
401: return transformer.transform(loader, className,
402: classBeingRedefined, protectionDomain,
403: classfileBuffer);
404: } else {
405: return null;
406: }
407: }
408: }
409:
410: public class FilteredChildFirstClassLoader extends URLClassLoader {
411: protected String packagePrefix;
412:
413: public FilteredChildFirstClassLoader(ClassLoader parent,
414: String packagePrefix) {
415: super (new URL[0], parent);
416: this .packagePrefix = packagePrefix;
417: }
418:
419: public Class loadClass(String name)
420: throws ClassNotFoundException {
421: return loadClass(name, false);
422: }
423:
424: protected synchronized Class loadClass(String name,
425: boolean resolve) throws ClassNotFoundException {
426: // see if we've already loaded it
427: Class c = findLoadedClass(name);
428: if (c != null) {
429: return c;
430: }
431:
432: if (!name.startsWith(packagePrefix)) {
433: return Class.forName(name, resolve, getParent());
434: }
435:
436: String resourceName = name.replace('.', '/') + ".class";
437: InputStream in = getResourceAsStream(resourceName);
438: if (in == null) {
439: throw new ClassNotFoundException(name);
440: }
441:
442: // 80% of class files are smaller then 6k
443: ByteArrayOutputStream bout = new ByteArrayOutputStream(
444: 8 * 1024);
445:
446: // copy the input stream into a byte array
447: byte[] bytes = new byte[0];
448: try {
449: byte[] buf = new byte[4 * 1024];
450: for (int count = -1; (count = in.read(buf)) >= 0;) {
451: bout.write(buf, 0, count);
452: }
453: bytes = bout.toByteArray();
454: } catch (IOException e) {
455: throw new ClassNotFoundException(name, e);
456: }
457:
458: // define the package
459: int packageEndIndex = name.lastIndexOf('.');
460: if (packageEndIndex != -1) {
461: String packageName = name.substring(0, packageEndIndex);
462: if (getPackage(packageName) == null) {
463: definePackage(packageName, null, null, null, null,
464: null, null, null);
465: }
466: }
467:
468: // define the class
469: try {
470: return defineClass(name, bytes, 0, bytes.length);
471: } catch (SecurityException e) {
472: // possible prohibited package: defer to the parent
473: return super.loadClass(name, resolve);
474: }
475: }
476: }
477: }
|