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


Reply via email to