You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2009/02/22 19:36:12 UTC

svn commit: r746794 - in /incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared: LauncherClassLoader.java Loader.java

Author: fmeschbe
Date: Sun Feb 22 18:36:12 2009
New Revision: 746794

URL: http://svn.apache.org/viewvc?rev=746794&view=rev
Log:
SLING-866 Create LauncherClassLoader shielding the launcher JAR from the
environment

Added:
    incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java   (with props)
Modified:
    incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java

Added: incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java?rev=746794&view=auto
==============================================================================
--- incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java (added)
+++ incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java Sun Feb 22 18:36:12 2009
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.sling.launchpad.base.shared;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * The <code>LauncherClassLoader</code> extends the standard Java VM
+ * <code>URLClassLoader</code> such, that classes and resources which are
+ * contained in the launcher JAR File are never looked up in the parent class
+ * loader.
+ * <p>
+ * This class loader shields the Sling OSGi framework completely from the
+ * environment because
+ * <ul>
+ * <li>Classes and resources contained in packages provided by the launcher JAR
+ * file are only looked up in the launcher JAR file</li>
+ * <li>Classes and resources from the environment are only used from within the
+ * framework if the framework is configured to do so by the
+ * <code>org.osgi.framework.bootdelegation</code> or
+ * <code>org.osgi.framework.systempackages</code> framework properties.</li>
+ * </ul>
+ * <p>
+ * The first point is important if Sling is deployed into any container, which
+ * provides some or all of the same packages as the Sling launcher JAR file. One
+ * such example is the Glassfish v3 Prelude application service, which itself
+ * runs in a Felix OSGi framework and sort of leaks the classes into the web
+ * application.
+ * <p>
+ * In the general case, we cannot prevent any leaking of classes, which may also
+ * be the OSGi core or compendium libraries, into Sling. So, this class loader
+ * is the barrier for this leaking and shields Sling from the environment unless
+ * explicitly configured to use this leaking.
+ * <p>
+ * Instances of this class loader are setup with the launcher JAR file as the
+ * only contents of the <code>URLClassLoaders</code> class path and the class
+ * loader of this class itself as the parent class loader.
+ */
+public class LauncherClassLoader extends URLClassLoader {
+
+    /**
+     * Set of packages never to be used from the environment. Each package is
+     * contained in this set in two forms: The Java package form where the
+     * segments are separated by dots, e.g. org.osgi.framework, and the resource
+     * form where the segments are separated by slash, e.g. org/osgi/framework.
+     * This makes checking packages for classes and resources equaly simple
+     * without requiring name mangling.
+     */
+    private final Set<String> launcherPackages;
+
+    LauncherClassLoader(File launcherJar) throws MalformedURLException {
+        super(new URL[] { launcherJar.toURL() },
+            LauncherClassLoader.class.getClassLoader());
+
+        Set<String> collectedPackages = new HashSet<String>();
+
+        JarFile jar = null;
+        try {
+            jar = new JarFile(launcherJar, false);
+            Enumeration<JarEntry> entries = jar.entries();
+            while (entries.hasMoreElements()) {
+                String entryName = entries.nextElement().getName();
+                if (entryName.endsWith(".class")
+                    && !entryName.startsWith("META-INF/")
+                    && !entryName.startsWith("javax/")) {
+                    String packageName = getPackageName(entryName, '/');
+                    if (packageName != null
+                        && collectedPackages.add(packageName)) {
+                        collectedPackages.add(packageName.replace('/', '.'));
+                    }
+                }
+            }
+        } catch (IOException ioe) {
+            // might log or throw, don't know ??
+        } finally {
+            if (jar != null) {
+                try {
+                    jar.close();
+                } catch (IOException ignore) {
+                }
+            }
+        }
+
+        launcherPackages = collectedPackages;
+    }
+
+    /**
+     * Load the name class and optionally resolve it, if found.
+     * <p>
+     * This method checks whether the package of the class is contained in the
+     * launcher JAR file. If so, the launcher JAR file is looked up for the
+     * class and class loading fails if not found. Otherwise the standard class
+     * loading strategy is applied by calling the base class implementation.
+     */
+    @Override
+    protected synchronized Class<?> loadClass(String name, boolean resolve)
+            throws ClassNotFoundException {
+        // First, check if the class has already been loaded
+        Class<?> c = findLoadedClass(name);
+        if (c == null) {
+            if (containsPackage(name, '.')) {
+                // finds the class or throws a ClassNotFoundException if
+                // the class cannot be found, which is ok, since we only
+                // want the class from our jar file, if it contains the
+                // package.
+                c = findClass(name);
+            } else {
+                return super.loadClass(name, resolve);
+            }
+        }
+
+        if (resolve) {
+            resolveClass(c);
+        }
+
+        return c;
+    }
+
+    /**
+     * Return an URL to the requested resource.
+     * <p>
+     * This method checks whether the package of the resource is contained in
+     * the launcher JAR file. If so, the launcher JAR file is looked up for the
+     * resource and resource access fails if not found. Otherwise the standard
+     * resource access strategy is applied by calling the base class
+     * implementation.
+     */
+    @Override
+    public URL getResource(String name) {
+
+        // if the package of the name is contained in our jar file
+        // file, return the resource or nothing
+        if (containsPackage(name, '/')) {
+            return findResource(name);
+        }
+
+        // try parent class loader only after having checked our packages
+        return super.getResource(name);
+    }
+
+    /**
+     * Returns the name of the package of the fully qualified name using the
+     * given <code>separator</code> as the segment separator. If the
+     * <code>name</code> does not contain the separator, the name is contained
+     * in the root package and this method returns <code>null</code>.
+     * <p>
+     * Example: Called for <i>org.osgi.framework.Bundle</i> this method returns
+     * <i>org.osgi.framework</i>.
+     * 
+     * @param name The fully qualified name of the class or resource to check
+     * @param separator The separator for package segments
+     */
+    private String getPackageName(String name, int separator) {
+        int speIdx = name.lastIndexOf(separator);
+        return (speIdx > 0) ? name.substring(0, speIdx) : null;
+    }
+
+    /**
+     * Returns <code>true</code> if the launcher JAR file provides the package
+     * to which the named class or resource belongs.
+     * 
+     * @param name The fully qualified name of the class or resource to check
+     * @param separator The separator for package segments
+     */
+    private boolean containsPackage(String name, int separator) {
+        String packageName = getPackageName(name, separator);
+        return (packageName == null)
+                ? false
+                : launcherPackages.contains(packageName);
+    }
+}

Propchange: incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java?rev=746794&r1=746793&r2=746794&view=diff
==============================================================================
--- incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java (original)
+++ incubator/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java Sun Feb 22 18:36:12 2009
@@ -61,17 +61,14 @@
                 + launcherJarFile + " is not accessible");
         }
 
-        URL launcherJarURL;
+        ClassLoader loader;
         try {
-            launcherJarURL = launcherJarFile.toURL();
+            loader = new LauncherClassLoader(launcherJarFile);
         } catch (MalformedURLException e) {
             throw new IllegalArgumentException(
                 "Cannot create an URL from the Sling Launcher JAR path name", e);
         }
 
-        ClassLoader loader = new URLClassLoader(new URL[] { launcherJarURL },
-            Loader.class.getClassLoader());
-
         try {
             Class<?> launcherClass = loader.loadClass(launcherClassName);
             return launcherClass.newInstance();