You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2012/07/12 23:30:35 UTC

svn commit: r1360960 - /openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/DeployTimeEnhancer.java

Author: rmannibucau
Date: Thu Jul 12 21:30:35 2012
New Revision: 1360960

URL: http://svn.apache.org/viewvc?rev=1360960&view=rev
Log:
TOMEE-280 more logic for deploy time enhancement

Modified:
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/DeployTimeEnhancer.java

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/DeployTimeEnhancer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/DeployTimeEnhancer.java?rev=1360960&r1=1360959&r2=1360960&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/DeployTimeEnhancer.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/DeployTimeEnhancer.java Thu Jul 12 21:30:35 2012
@@ -1,26 +1,44 @@
 package org.apache.openejb.assembler.classic;
 
 import org.apache.openejb.config.event.BeforeDeploymentEvent;
+import org.apache.openejb.config.sys.ListAdapter;
+import org.apache.openejb.config.sys.ServiceProvider;
 import org.apache.openejb.loader.Files;
 import org.apache.openejb.observer.Observes;
+import org.apache.openejb.util.JarExtractor;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
 import org.apache.openejb.util.URLs;
-
+import org.xml.sax.Attributes;
+import org.xml.sax.HandlerBase;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
 import java.io.File;
 import java.io.FileFilter;
+import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Properties;
+import java.util.*;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
 
 public class DeployTimeEnhancer {
     private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_DEPLOY, DeployTimeEnhancer.class);
-    public static final String CLASS_EXT = ".class";
-    public static final String PROPERTIES_FILE_PROP = "propertiesFile";
+    private static final SAXParserFactory SAX_PARSER_FACTORY = SAXParserFactory.newInstance();
+
+    private static final String CLASS_EXT = ".class";
+    private static final String PROPERTIES_FILE_PROP = "propertiesFile";
+    private static final String META_INF_PERSISTENCE_XML = "META-INF/persistence.xml";
+
+    static {
+        SAX_PARSER_FACTORY.setNamespaceAware(true);
+        SAX_PARSER_FACTORY.setValidating(false);
+    }
 
     private final Method enhancerMethod;
     private final Constructor<?> optionsConstructor;
@@ -43,84 +61,123 @@ public class DeployTimeEnhancer {
         enhancerMethod = mtd;
     }
 
-    // TODO: manage jars: unpack();enhance();repack();
-    public void enhance(@Observes BeforeDeploymentEvent event) {
+    public void enhance(@Observes final BeforeDeploymentEvent event) {
         if (enhancerMethod == null) {
             LOGGER.debug("OpenJPA is not available so no deploy-time enhancement will be done");
             return;
         }
 
-        /*
-        algorithm could be something like:
-        1) browsing all urls (event.getUrls()) to get unpacked persistence.xml and packed persistence.xml (in jar)
-        2) for each url parse it with a small sax parser to get jar-file for each one --> list of jar needed by pu
-        3) for each persistence.xml aggregate file needed (all of jars, include/exclude could be nice)
-        4) for each persistence.xml run enhancer
-        5) for all jar unpacked repack it and replace original one
-        6) clean up unpacked jar (don't delete already unpacked folder like WEB-INF/classes ;))
-         */
-
-        final Properties opts = options(event.getUrls());
-        final Object optsArg;
-        try {
-            optsArg = optionsConstructor.newInstance(opts);
-        } catch (Exception e) {
-            LOGGER.debug("can't create options for enhancing");
-            return;
+        // find persistence.xml
+        final Map<String, List<String>> classesByPXml = new HashMap<String, List<String>>();
+        for (URL url : event.getUrls()) {
+            final File file = URLs.toFile(url);
+            if (file.isDirectory()) {
+                final String pXmls = getWarPersistenceXml(url);
+                if (pXmls != null) {
+                    feed(classesByPXml, pXmls);
+                }
+            } else if (file.getName().endsWith(".jar")) {
+                try {
+                    final JarFile jar = new JarFile(file);
+                    ZipEntry entry = jar.getEntry(META_INF_PERSISTENCE_XML);
+                    if (entry != null) {
+                        final String path = file.getAbsolutePath();
+                        final File unpacked = new File(path.substring(0, path.length() - 4));
+                        JarExtractor.extract(file, unpacked);
+                        feed(classesByPXml, new File(unpacked, META_INF_PERSISTENCE_XML).getAbsolutePath());
+                    }
+                } catch (IOException e) {
+                    // ignored
+                }
+            }
         }
 
-        if (opts.containsKey(PROPERTIES_FILE_PROP)) {
+        // enhancement
+        for (Map.Entry<String, List<String>> entry : classesByPXml.entrySet()) {
+            final Properties opts = new Properties();
+            opts.setProperty(PROPERTIES_FILE_PROP, entry.getKey());
+
+            final Object optsArg;
+            try {
+                optsArg = optionsConstructor.newInstance(opts);
+            } catch (Exception e) {
+                LOGGER.debug("can't create options for enhancing");
+                return;
+            }
+
             LOGGER.info("enhancing url(s): " + Arrays.asList(event.getUrls()));
-            // TODO: manage lib folder
             try {
-                enhancerMethod.invoke(null, toFilePaths(event.getUrls()), optsArg);
+                enhancerMethod.invoke(null, toFilePaths(entry.getValue()), optsArg);
             } catch (Exception e) {
                 LOGGER.warning("can't enhanced at deploy-time entities", e);
             }
-        } else {
-            LOGGER.debug("no persistence.xml so no enhancing");
         }
-    }
 
-    private Properties options(final URL[] urls) {
-        final Properties props = new Properties();
-        final String pXmls = getWarPersistenceXml(urls);
-        if (!pXmls.isEmpty()) {
-            props.setProperty(PROPERTIES_FILE_PROP, pXmls);
+        // clean up extracted jars
+        for (Map.Entry<String, List<String>> entry : classesByPXml.entrySet()) {
+            final List<String> values = entry.getValue();
+            for (String path : values) {
+                final File file = new File(path + ".jar");
+                if (file.exists()) {
+                    Files.delete(file);
+                }
+            }
+            values.clear();
         }
-        return props;
+
+        classesByPXml.clear();
     }
 
-    private String getWarPersistenceXml(final URL[] urls) { // META-INF/persistence.xml will be managed by jar, not here
-        final StringBuilder files = new StringBuilder();
-        for (URL url : urls) {
-            final File dir = URLs.toFile(url);
-            if (!dir.isDirectory()) {
-                continue;
+    private void feed(final Map<String, List<String>> classesByPXml, final String pXml) {
+        final List<String> paths = new ArrayList<String>();
+
+        // first add the classes directory where is the persistence.xml
+        if (pXml.endsWith(META_INF_PERSISTENCE_XML)) {
+            paths.add(pXml.substring(0, pXml.length() - META_INF_PERSISTENCE_XML.length()));
+        } else if (pXml.endsWith("/WEB-INF/persistence.xml")) {
+            paths.add(pXml.substring(0, pXml.length() - 24));
+        }
+
+        // then jar-file
+        try {
+            final SAXParser parser = SAX_PARSER_FACTORY.newSAXParser();
+            final JarFileParser handler = new JarFileParser();
+            parser.parse(new File(pXml), handler);
+            for (String path : handler.getPaths()) {
+                paths.add(relative(paths.iterator().next(), path));
             }
+        } catch (Exception e) {
+            LOGGER.error("can't parse '" + pXml + "'", e);
+        }
 
-            if (dir.getAbsolutePath().endsWith("/WEB-INF/classes")) {
-                final File pXml = new File(dir, "META-INF/persistence.xml");
-                if (pXml.exists()) {
-                    files.append(pXml.getAbsolutePath());
-                }
+        classesByPXml.put(pXml, paths);
+    }
 
-                final File pXml2 = new File(dir.getParentFile(), "persistence.xml");
-                if (pXml2.exists()) {
-                    if (!files.toString().isEmpty()) {
-                        files.append(",");
-                    }
-                    files.append(pXml2.getAbsolutePath());
-                }
+    // relativePath = relative path to the jar file containing the persistence.xml
+    private String relative(final String relativePath, final String pXmlPath) {
+        return new File(new File(pXmlPath).getParent(), relativePath).getAbsolutePath();
+    }
+
+    private String getWarPersistenceXml(final URL url) {
+        final File dir = URLs.toFile(url);
+        if (dir.isDirectory() && dir.getAbsolutePath().endsWith("/WEB-INF/classes")) {
+            final File pXmlStd = new File(dir.getParentFile(), "persistence.xml");
+            if (pXmlStd.exists()) {
+                return  pXmlStd.getAbsolutePath();
+            }
+
+            final File pXml = new File(dir, META_INF_PERSISTENCE_XML);
+            if (pXml.exists()) {
+                return pXml.getAbsolutePath();
             }
         }
-        return files.toString();
+        return null;
     }
 
-    private String[] toFilePaths(final URL[] urls) {
+    private String[] toFilePaths(final List<String> urls) {
         final List<String> files = new ArrayList<String>();
-        for (URL url : urls) {
-            final File dir = URLs.toFile(url);
+        for (String url : urls) {
+            final File dir = new File(url);
             if (!dir.isDirectory()) {
                 continue;
             }
@@ -138,4 +195,34 @@ public class DeployTimeEnhancer {
             return file.getName().endsWith(CLASS_EXT);
         }
     }
+
+    private static class JarFileParser extends DefaultHandler {
+        private final List<String> paths = new ArrayList<String>();
+        private boolean getIt = false;
+
+        @Override
+        public void startElement(final String uri, final String localName, final String qName, final Attributes att) throws SAXException {
+            if (!localName.endsWith("jar-file")) {
+                return;
+            }
+
+            getIt = true;
+        }
+
+        @Override
+        public void characters(final char ch[], final int start, final int length) throws SAXException {
+            if (getIt) {
+                paths.add(new StringBuilder().append(ch, start, length).toString());
+            }
+        }
+
+        @Override
+        public void endElement(final String uri, final String localName, final String qName) throws SAXException {
+            getIt = false;
+        }
+
+        public List<String> getPaths() {
+            return paths;
+        }
+    }
 }