You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomee.apache.org by Romain Manni-Bucau <rm...@gmail.com> on 2014/07/16 13:22:45 UTC
Fwd: svn commit: r1610966 - /tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
Please revert it since it is not finished. Pushed it on gist to share
my current status but it breaks more (=fastest so maybe good) tests.
Some more work needs to be done (and a little refactoring for perfs
but that's a detail) before we can use it.
Side note: we'll surely need to do the same for normal jpa entities -
didnt take time to evaluate it yet and can not be as mandatory as this
one for 1.7
Romain Manni-Bucau
Twitter: @rmannibucau
Blog: http://rmannibucau.wordpress.com/
LinkedIn: http://fr.linkedin.com/in/rmannibucau
Github: https://github.com/rmannibucau
---------- Forwarded message ----------
From: <an...@apache.org>
Date: 2014-07-16 13:05 GMT+02:00
Subject: svn commit: r1610966 -
/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
To: commits@tomee.apache.org
Author: andygumbrecht
Date: Wed Jul 16 11:05:34 2014
New Revision: 1610966
URL: http://svn.apache.org/r1610966
Log:
Romains enhance patch
Modified:
tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
Modified: tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java?rev=1610966&r1=1610965&r2=1610966&view=diff
==============================================================================
--- tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
(original)
+++ tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
Wed Jul 16 11:05:34 2014
@@ -17,6 +17,8 @@
package org.apache.openejb.assembler.classic;
+import org.apache.commons.lang3.JavaVersion;
+import org.apache.commons.lang3.SystemUtils;
import org.apache.openejb.ClassLoaderUtil;
import org.apache.openejb.core.cmp.CmpUtil;
import org.apache.openejb.core.cmp.cmp2.Cmp1Generator;
@@ -27,9 +29,33 @@ import org.apache.openejb.loader.SystemI
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.UrlCache;
-
+import org.apache.openejb.util.classloader.URLClassLoaderFirst;
+import org.apache.openjpa.enhance.PCEnhancer;
+import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
+import org.apache.openjpa.jdbc.meta.MappingRepository;
+import org.apache.openjpa.jdbc.meta.NoneMappingDefaults;
+import org.apache.openjpa.jdbc.sql.HSQLDictionary;
+import org.apache.openjpa.lib.util.BytecodeWriter;
+import org.apache.openjpa.meta.AccessCode;
+import org.apache.openjpa.meta.MetaDataModes;
+import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.persistence.jdbc.PersistenceMappingFactory;
+import org.apache.xbean.asm5.ClassReader;
+import org.apache.xbean.asm5.ClassWriter;
+import serp.bytecode.BCClass;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
@@ -80,15 +106,53 @@ public class CmpJarBuilder {
jarOutputStream = openJarFile(this);
// Generate CMP implementation classes
+ final Map<String, Entry> classes = new HashMap<>();
for (final EjbJarInfo ejbJar : appInfo.ejbJars) {
for (final EnterpriseBeanInfo beanInfo :
ejbJar.enterpriseBeans) {
if (beanInfo instanceof EntityBeanInfo) {
final EntityBeanInfo entityBeanInfo =
(EntityBeanInfo) beanInfo;
if
("CONTAINER".equalsIgnoreCase(entityBeanInfo.persistenceType)) {
- generateClass(jarOutputStream, entityBeanInfo);
+ final Entry entry =
generateClass(jarOutputStream, entityBeanInfo);
+ classes.put(entry.clazz, entry);
+ }
+ }
+ }
+ }
+
+ final URLClassLoaderFirst thisClassLoader = new
URLClassLoaderFirst(new URL[0], tempClassLoader) {
+ @Override
+ public Class<?> loadClass(final String name, final
boolean resolve) throws ClassNotFoundException {
+ final Entry e = classes.get(name);
+ if (e != null) {
+ final Class<?> alreadyLoaded = findLoadedClass(name);
+ if (alreadyLoaded != null) {
+ if (resolve) {
+ resolveClass(alreadyLoaded);
+ }
+ return alreadyLoaded;
}
+
+ final Class<?> c = defineClass(e.clazz,
e.bytes, 0, e.bytes.length);
+ if (resolve) {
+ resolveClass(c);
+ }
+ return c;
}
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ public InputStream getResourceAsStream(final String name) {
+ final String key = name.replace('/',
'.').replace(".class", "");
+ final Entry e = classes.get(key);
+ return e != null ? new
ByteArrayInputStream(e.bytes) : super.getResourceAsStream(name);
}
+ };
+
+
+ for (final Entry e : classes.values()) {
+ // add the generated class to the jar
+ addJarEntry(jarOutputStream, e.name,
enhance(thisClassLoader, e.clazz, e.bytes));
}
if (appInfo.cmpMappingsXml != null) {
// System.out.println(appInfo.cmpMappingsXml);
@@ -140,12 +204,12 @@ public class CmpJarBuilder {
* @param entityBeanInfo The descriptor for the entity bean we
need to wrapper.
* @throws IOException
*/
- private void generateClass(final JarOutputStream jarOutputStream,
final EntityBeanInfo entityBeanInfo) throws IOException {
+ private Entry generateClass(final JarOutputStream
jarOutputStream, final EntityBeanInfo entityBeanInfo) throws
IOException {
// don't generate if there is aleady an implementation class
final String cmpImplClass =
CmpUtil.getCmpImplClassName(entityBeanInfo.abstractSchemaName,
entityBeanInfo.ejbClass);
final String entryName = cmpImplClass.replace(".", "/") + ".class";
if (entries.contains(entryName) ||
tempClassLoader.getResource(entryName) != null) {
- return;
+ return null;
}
// load the bean class, which is used by the generator
@@ -201,8 +265,7 @@ public class CmpJarBuilder {
bytes = cmp2Generator.generate();
}
- // add the generated class to the jar
- addJarEntry(jarOutputStream, entryName, bytes);
+ return new Entry(cmpImplClass, entryName, bytes);
}
/**
@@ -239,6 +302,81 @@ public class CmpJarBuilder {
}
}
+ private byte[] enhance(final ClassLoader thisClassLoader, final
String clazz, final byte[] bytes) {
+ try {
+ final ByteArrayOutputStream baos = new
ByteArrayOutputStream(bytes.length * 2);
+ final JDBCConfigurationImpl conf = new JDBCConfigurationImpl();
+ conf.setDBDictionary(new HSQLDictionary());
+ final MappingRepository repos = new MappingRepository();
+
+ final Class<?> tmpClass = thisClassLoader.loadClass(clazz);
+ repos.setConfiguration(conf);
+ repos.setMetaDataFactory(new PersistenceMappingFactory() {
+ @Override
+ public Set getPersistentTypeNames(boolean devpath,
ClassLoader envLoader) {
+ return Collections.singleton(tmpClass);
+ }
+ });
+ repos.setMappingDefaults(NoneMappingDefaults.getInstance());
+ repos.setResolve(MetaDataModes.MODE_NONE);
+ repos.setValidate(MetaDataRepository.VALIDATE_NONE);
+ repos.addMetaData(tmpClass, AccessCode.PROPERTY);
+
+ final PCEnhancer.Flags flags = new PCEnhancer.Flags();
+ flags.tmpClassLoader = false;
+
+ final BytecodeWriter writer = new BytecodeWriter() {
+ @Override
+ public void write(final BCClass type) throws IOException {
+ final byte[] b = type.toByteArray();
+ if
(SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_7)) {
+ final ByteArrayInputStream bais = new
ByteArrayInputStream(b);
+ final BufferedInputStream bis = new
BufferedInputStream(bais);
+
+ final ClassWriter cw = new
ClassWriter(ClassWriter.COMPUTE_FRAMES) {
+ protected String
getCommonSuperClass(String type1, String type2) {
+ Class<?> class1;
+ Class<?> class2;
+ try {
+ class1 =
thisClassLoader.loadClass(type1.replace('/', '.'));
+ class2 =
thisClassLoader.loadClass(type2.replace('/', '.'));
+ } catch (final ClassNotFoundException ex) {
+ throw new RuntimeException(ex);
+ }
+ if (class1.isAssignableFrom(class2)) {
+ return type1;
+ }
+ if (class2.isAssignableFrom(class1)) {
+ return type2;
+ }
+ if (class1.isInterface() ||
class2.isInterface()) {
+ return "java/lang/Object";
+ }
+ do {
+ class1 = class1.getSuperclass();
+ } while (!class1.isAssignableFrom(class2));
+ return class1.getName().replace('.', '/');
+ }
+ };
+ final ClassReader cr = new ClassReader(bis);
+ cr.accept(cw, 0);
+ baos.write(cw.toByteArray());
+ } else {
+ baos.write(b);
+ }
+ }
+ };
+ PCEnhancer.run(conf, null, flags, repos, writer, thisClassLoader);
+ final byte[] enhanced = baos.toByteArray();
+ if (enhanced.length > 0) {
+ return enhanced;
+ }
+ } catch (final Exception e) {
+ // no-op: we should surely log something, maybe a warning
+ }
+ return bytes;
+ }
+
private static synchronized JarOutputStream openJarFile(final
CmpJarBuilder instance) throws IOException {
if (instance.jarFile != null) {
@@ -286,4 +424,16 @@ public class CmpJarBuilder {
}
}
}
-}
+
+ private static class Entry {
+ private final String clazz;
+ private final String name;
+ private final byte[] bytes;
+
+ private Entry(final String clazz, final String name, final
byte[] bytes) {
+ this.clazz = clazz;
+ this.name = name;
+ this.bytes = bytes;
+ }
+ }
+}
\ No newline at end of file