You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2006/02/07 15:45:59 UTC

svn commit: r375617 - in /incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix: framework/cache/DefaultBundleArchive.java moduleloader/ContentDirectoryContent.java moduleloader/JarContent.java moduleloader/JarFileX.java

Author: rickhall
Date: Tue Feb  7 06:45:57 2006
New Revision: 375617

URL: http://svn.apache.org/viewcvs?rev=375617&view=rev
Log:
Implemented initial support for embedded directories on the Bundle-ClassPath.
In the process uncovered an apparent bug in the JVM where ZIP entries
that correspond to directories are not correctly being identified as
directories.

Added:
    incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ContentDirectoryContent.java   (with props)
    incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarFileX.java   (with props)
Modified:
    incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java
    incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarContent.java

Modified: incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java?rev=375617&r1=375616&r2=375617&view=diff
==============================================================================
--- incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java (original)
+++ incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/DefaultBundleArchive.java Tue Feb  7 06:45:57 2006
@@ -19,13 +19,11 @@
 import java.io.*;
 import java.security.*;
 import java.util.*;
-import java.util.jar.JarFile;
 import java.util.jar.Manifest;
 import java.util.zip.ZipEntry;
 
 import org.apache.felix.framework.Logger;
 import org.apache.felix.framework.util.*;
-import org.apache.felix.framework.util.Util;
 import org.apache.felix.moduleloader.*;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
@@ -694,28 +692,17 @@
             m_dir, REVISION_DIRECTORY + getRefreshCount() + "." + revision);
 
         // Get the embedded resource.
-        JarFile jarFile = null;
+        JarFileX jarFile = null;
 
         try
         {
-            // Create JarFile object using privileged block.
-            if (System.getSecurityManager() != null)
-            {
-                jarFile = (JarFile) AccessController.doPrivileged(
-                    new PrivilegedAction(
-                        PrivilegedAction.OPEN_BUNDLE_JAR_ACTION, this, revisionDir));
-            }
-            else
-            {
-                jarFile = openBundleJarUnchecked(revisionDir);
-            }
-
+            // Open bundle JAR file.
+            jarFile = openBundleJar(revisionDir);
             // Error if no jar file.
             if (jarFile == null)
             {
                 throw new IOException("No JAR file found.");
             }
-
             // Get manifest.
             Manifest mf = jarFile.getManifest();
             // Create a case insensitive map of manifest attributes.
@@ -728,20 +715,40 @@
             }
             return map;
 
-        } catch (PrivilegedActionException ex) {
-            throw ((PrivilegedActionException) ex).getException();
-        } finally {
+        }
+        finally
+        {
             if (jarFile != null) jarFile.close();
         }
     }
 
-    private JarFile openBundleJarUnchecked(File revisionDir)
+    private JarFileX openBundleJarUnchecked(File revisionDir)
         throws Exception
     {
         // Get bundle jar file.
         File bundleJar = new File(revisionDir, BUNDLE_JAR_FILE);
         // Get bundle jar file.
-        return new JarFile(bundleJar);
+        return new JarFileX(bundleJar);
+    }
+
+    private JarFileX openBundleJar(File revisionDir) throws Exception
+    {
+        // Create JarFile object using privileged block.
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                return (JarFileX) AccessController.doPrivileged(
+                    new PrivilegedAction(
+                        PrivilegedAction.OPEN_BUNDLE_JAR_ACTION, this, revisionDir));
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw ((PrivilegedActionException) ex).getException();
+            }
+        }
+
+        return openBundleJarUnchecked(revisionDir);
     }
 
     private IContent getContentUnchecked(int revision)
@@ -823,28 +830,47 @@
         }
 
         // Create the bundles class path.
-        IContent self = new JarContent(new File(revisionDir, BUNDLE_JAR_FILE));
-        IContent[] classPath = new IContent[classPathStrings.length];
-        for (int i = 0; i < classPathStrings.length; i++)
+        JarFileX bundleJar = null;
+        try
         {
-            if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
+            bundleJar = openBundleJar(revisionDir);
+            IContent self = new JarContent(new File(revisionDir, BUNDLE_JAR_FILE));
+            IContent[] classPath = new IContent[classPathStrings.length];
+            for (int i = 0; i < classPathStrings.length; i++)
             {
-                classPath[i] = self;
+                if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
+                {
+                    classPath[i] = self;
+                }
+                else
+                {
+                    // Determine if the class path entry is a file or directory
+                    // in the bundle JAR file.
+                    ZipEntry entry = bundleJar.getEntry(classPathStrings[i]);
+                    if ((entry != null) && entry.isDirectory())
+                    {
+                        classPath[i] = new ContentDirectoryContent(self, classPathStrings[i]);
+                    }
+                    else
+                    {
+                        classPath[i] = new JarContent(new File(embedDir, classPathStrings[i]));
+                    }
+                }
             }
-            else
+    
+            // If there is nothing on the class path, then include
+            // "." by default, as per the spec.
+            if (classPath.length == 0)
             {
-                classPath[i] = new JarContent(new File(embedDir, classPathStrings[i]));
+                classPath = new IContent[] { self };
             }
-        }
 
-        // If there is nothing on the class path, then include
-        // "." by default, as per the spec.
-        if (classPath.length == 0)
+            return classPath;
+        }
+        finally
         {
-            classPath = new IContent[] { self };
+            if (bundleJar != null) bundleJar.close();
         }
-
-        return classPath;
     }
 
     public IContent[] getContentPath(int revision)
@@ -906,7 +932,7 @@
         // already exist.
         if (!libFile.exists())
         {
-            JarFile jarFile = null;
+            JarFileX jarFile = null;
             InputStream is = null;
 
             try
@@ -1077,7 +1103,9 @@
             byte[] b = new byte[DefaultBundleCache.BUFSIZE];
             int len = 0;
             while ((len = is.read(b)) != -1)
+            {
                 os.write(b, 0, len);
+            }
         }
         finally
         {
@@ -1132,17 +1160,7 @@
             }
 
             // Find class path meta-data.
-            String classPath = null;
-            Iterator iter = map.entrySet().iterator();
-            while ((classPath == null) && iter.hasNext())
-            {
-                Map.Entry entry = (Map.Entry) iter.next();
-                if (entry.getKey().toString().toLowerCase().equals(
-                    FelixConstants.BUNDLE_CLASSPATH.toLowerCase()))
-                {
-                    classPath = entry.getValue().toString();
-                }
-            }
+            String classPath = map.get(FelixConstants.BUNDLE_CLASSPATH).toString();
 
             // Parse the class path into strings.
             String[] classPathStrings = Util.parseDelimitedString(
@@ -1183,45 +1201,48 @@
         // Remove leading slash if present.
         jarPath = (jarPath.charAt(0) == '/') ? jarPath.substring(1) : jarPath;
 
-        // If JAR is already extracted, then don't
-        // re-extract it...
+        // If JAR is already extracted, then don't re-extract it...
         File jarFile = new File(
             revisionDir, EMBEDDED_DIRECTORY + File.separatorChar + jarPath);
 
         if (!jarFile.exists())
         {
-            // Make sure that the embedded JAR's parent directory exists;
-            // it may be in a sub-directory.
-            File jarDir = jarFile.getParentFile();
-            if (!jarDir.exists())
-            {
-                if (!jarDir.mkdirs())
-                {
-                    throw new IOException("Unable to create embedded JAR directory.");
-                }
-            }
-
-            // Extract embedded JAR into its directory.
-            JarFile bundleJar = null;
+            JarFileX bundleJar = null;
             InputStream is = null;
-
             try
             {
+                // Make sure class path entry is a JAR file.
                 bundleJar = openBundleJarUnchecked(revisionDir);
                 ZipEntry ze = bundleJar.getEntry(jarPath);
                 if (ze == null)
                 {
                     throw new IOException("No JAR entry: " + jarPath);
                 }
-                is = new BufferedInputStream(bundleJar.getInputStream(ze), DefaultBundleCache.BUFSIZE);
-                if (is == null)
+                // If the zip entry is a directory, then ignore it since
+                // we don't need to extact it; otherwise, it points to an
+                // embedded JAR file, so extract it.
+                else if (!ze.isDirectory())
                 {
-                    throw new IOException("No input stream: " + jarPath);
+                    // Make sure that the embedded JAR's parent directory exists;
+                    // it may be in a sub-directory.
+                    File jarDir = jarFile.getParentFile();
+                    if (!jarDir.exists())
+                    {
+                        if (!jarDir.mkdirs())
+                        {
+                            throw new IOException("Unable to create embedded JAR directory.");
+                        }
+                    }
+    
+                    // Extract embedded JAR into its directory.
+                    is = new BufferedInputStream(bundleJar.getInputStream(ze), DefaultBundleCache.BUFSIZE);
+                    if (is == null)
+                    {
+                        throw new IOException("No input stream: " + jarPath);
+                    }
+                    // Copy the file.
+                    copy(is, jarFile);
                 }
-
-                // Create the file.
-                copy(is, jarFile);
-
             }
             finally
             {

Added: incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ContentDirectoryContent.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ContentDirectoryContent.java?rev=375617&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ContentDirectoryContent.java (added)
+++ incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ContentDirectoryContent.java Tue Feb  7 06:45:57 2006
@@ -0,0 +1,134 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed 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.felix.moduleloader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+
+public class ContentDirectoryContent implements IContent
+{
+    private IContent m_content = null;
+    private String m_path = null;
+    private boolean m_opened = false;
+
+    public ContentDirectoryContent(IContent content, String path)
+    {
+        m_content = content;
+        // Add a '/' to the end if not present.
+        m_path = (path.length() > 0) && (path.charAt(path.length() - 1) != '/')
+            ? path + "/" : path;
+    }
+
+    protected void finalize()
+    {
+        if (m_content != null)
+        {
+            m_content.close();
+        }
+    }
+
+    public void open()
+    {
+        m_content.open();
+        m_opened = true;
+    }
+
+    public synchronized void close()
+    {
+        try
+        {
+            if (m_content != null)
+            {
+                m_content.close();
+            }
+        }
+        catch (Exception ex)
+        {
+            System.err.println("JarContent: " + ex);
+        }
+
+        m_content = null;
+        m_opened = false;
+    }
+
+    public synchronized boolean hasEntry(String name) throws IllegalStateException
+    {
+        if (!m_opened)
+        {
+            throw new IllegalStateException("ContentDirectoryContent is not open");
+        }
+
+        if (name.charAt(0) == '/')
+        {
+            name = name.substring(1);
+        }
+
+        return m_content.hasEntry(m_path + name);
+    }
+
+    public synchronized byte[] getEntry(String name) throws IllegalStateException
+    {
+        if (!m_opened)
+        {
+            throw new IllegalStateException("ContentDirectoryContent is not open");
+        }
+
+        if (name.charAt(0) == '/')
+        {
+            name = name.substring(1);
+        }
+
+        return m_content.getEntry(m_path + name);
+    }
+
+    public synchronized InputStream getEntryAsStream(String name)
+        throws IllegalStateException, IOException
+    {
+        if (!m_opened)
+        {
+            throw new IllegalStateException("ContentDirectoryContent is not open");
+        }
+
+        if (name.charAt(0) == '/')
+        {
+            name = name.substring(1);
+        }
+
+        return m_content.getEntryAsStream(m_path + name);
+    }
+
+    public synchronized Enumeration getEntryPaths(String path)
+    {
+        if (!m_opened)
+        {
+            throw new IllegalStateException("ContentDirectoryContent is not open");
+        }
+
+        if (path.charAt(0) == '/')
+        {
+            path = path.substring(1);
+        }
+
+        return m_content.getEntryPaths(m_path + path);
+    }
+
+    public String toString()
+    {
+        return "CONTENT DIR " + m_path + " (" + m_content + ")";
+    }
+}
\ No newline at end of file

Propchange: incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/ContentDirectoryContent.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarContent.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarContent.java?rev=375617&r1=375616&r2=375617&view=diff
==============================================================================
--- incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarContent.java (original)
+++ incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarContent.java Tue Feb  7 06:45:57 2006
@@ -19,7 +19,6 @@
 import java.io.*;
 import java.util.Enumeration;
 import java.util.NoSuchElementException;
-import java.util.jar.JarFile;
 import java.util.zip.ZipEntry;
 
 public class JarContent implements IContent
@@ -27,7 +26,7 @@
     private static final int BUFSIZE = 4096;
 
     private File m_file = null;
-    private JarFile m_jarFile = null;
+    private JarFileX m_jarFile = null;
     private boolean m_opened = false;
 
     public JarContent(File file)
@@ -255,7 +254,7 @@
     {
         if (m_jarFile == null)
         {
-            m_jarFile = new JarFile(m_file);
+            m_jarFile = new JarFileX(m_file);
         }
     }
 

Added: incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarFileX.java
URL: http://svn.apache.org/viewcvs/incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarFileX.java?rev=375617&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarFileX.java (added)
+++ incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarFileX.java Tue Feb  7 06:45:57 2006
@@ -0,0 +1,86 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed 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.felix.moduleloader;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+/**
+ * The purpose of this class is to fix an apparent bug in the JVM in versions
+ * 1.4.2 and lower where directory entries in ZIP/JAR files are not correctly
+ * identified.
+**/
+public class JarFileX extends JarFile
+{
+    public JarFileX(File file) throws IOException
+    {
+        super(file);
+    }
+
+    public JarFileX(File file, boolean verify) throws IOException
+    {
+        super(file, verify);
+    }
+
+    public JarFileX(File file, boolean verify, int mode) throws IOException
+    {
+        super(file, verify, mode);
+    }
+
+    public JarFileX(String name) throws IOException
+    {
+        super(name);
+    }
+
+    public JarFileX(String name, boolean verify) throws IOException
+    {
+        super(name, verify);
+    }
+
+    public ZipEntry getEntry(String name)
+    {
+        ZipEntry entry = super.getEntry(name);
+        if ((entry != null) && (entry.getSize() == 0) && !entry.isDirectory())
+        {
+            ZipEntry dirEntry = super.getEntry(name + '/');
+            if (dirEntry != null)
+            {
+                entry = dirEntry;
+            }
+        }
+        return entry;
+    }
+
+    public JarEntry getJarEntry(String name)
+    {
+        JarEntry entry = super.getJarEntry(name);
+        if ((entry != null) && (entry.getSize() == 0) && !entry.isDirectory())
+        {
+            JarEntry dirEntry = super.getJarEntry(name + '/');
+            if (dirEntry != null)
+            {
+                entry = dirEntry;
+            }
+        }
+        return entry;
+    }
+
+
+}

Propchange: incubator/felix/trunk/org.apache.felix.framework/src/main/java/org/apache/felix/moduleloader/JarFileX.java
------------------------------------------------------------------------------
    svn:eol-style = native