changeset 3482:0f5dc2fc81b1

6887710: Jar index should avoid putting META-INF in the INDEX.LIST Reviewed-by: michaelm
author chegar
date Thu, 03 Feb 2011 11:56:56 +0000
parents dff9b6d18628
children 68e3eba12afe
files src/share/classes/sun/misc/JarIndex.java test/sun/misc/JarIndex/metaInfFilenames/Basic.java test/sun/misc/JarIndex/metaInfFilenames/jarA/META-INF/services/my.happy.land test/sun/misc/JarIndex/metaInfFilenames/jarA/a/A.java test/sun/misc/JarIndex/metaInfFilenames/jarA/com/message/spi/MessageService.java test/sun/misc/JarIndex/metaInfFilenames/jarB/META-INF/JAVA2.DS test/sun/misc/JarIndex/metaInfFilenames/jarB/META-INF/services/no.name.service test/sun/misc/JarIndex/metaInfFilenames/jarB/b/B.java test/sun/misc/JarIndex/metaInfFilenames/jarC/META-INF/fonts.mf test/sun/misc/JarIndex/metaInfFilenames/jarC/META-INF/fonts/Company-corporate.ttf test/sun/misc/JarIndex/metaInfFilenames/jarC/META-INF/fonts/kidpr.ttf test/sun/misc/JarIndex/metaInfFilenames/jarC/META-INF/services/com.message.spi.MessageService test/sun/misc/JarIndex/metaInfFilenames/jarC/my/impl/StandardMessageService.java
diffstat 13 files changed, 784 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/sun/misc/JarIndex.java	Thu Feb 03 11:28:04 2011 +0000
+++ b/src/share/classes/sun/misc/JarIndex.java	Thu Feb 03 11:56:56 2011 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -67,6 +67,14 @@
     public static final String INDEX_NAME = "META-INF/INDEX.LIST";
 
     /**
+     * true if, and only if, sun.misc.JarIndex.metaInfFilenames is set to true.
+     * If true, the names of the files in META-INF, and its subdirectories, will
+     * be added to the index. Otherwise, just the directory names are added.
+     */
+    private static final boolean metaInfFilenames =
+        "true".equals(System.getProperty("sun.misc.JarIndex.metaInfFilenames"));
+
+    /**
      * Constructs a new, empty jar index.
      */
     public JarIndex() {
@@ -187,6 +195,18 @@
     }
 
     /**
+     * Same as add(String,String) except that it doesn't strip off from the
+     * last index of '/'. It just adds the filename.
+     */
+    private void addExplicit(String fileName, String jarName) {
+        // add the mapping to indexMap
+        addToList(fileName, jarName, indexMap);
+
+        // add the mapping to jarMap
+        addToList(jarName, fileName, jarMap);
+     }
+
+    /**
      * Go through all the jar files and construct the
      * index table.
      */
@@ -204,15 +224,31 @@
 
             Enumeration entries = zrf.entries();
             while(entries.hasMoreElements()) {
-                String fileName = ((ZipEntry)(entries.nextElement())).getName();
-                // Index the META-INF directory, but not the index or manifest.
-                if (!fileName.startsWith("META-INF/") ||
-                        !(fileName.equals("META-INF/") ||
-                          fileName.equals(INDEX_NAME) ||
-                          fileName.equals(JarFile.MANIFEST_NAME))) {
+                ZipEntry entry = (ZipEntry) entries.nextElement();
+                String fileName = entry.getName();
+
+                // Skip the META-INF directory, the index, and manifest.
+                // Any files in META-INF/ will be indexed explicitly
+                if (fileName.equals("META-INF/") ||
+                    fileName.equals(INDEX_NAME) ||
+                    fileName.equals(JarFile.MANIFEST_NAME))
+                    continue;
+
+                if (!metaInfFilenames) {
                     add(fileName, currentJar);
+                } else {
+                    if (!fileName.startsWith("META-INF/")) {
+                        add(fileName, currentJar);
+                    } else if (!entry.isDirectory()) {
+                        // Add files under META-INF explicitly so that certain
+                        // services, like ServiceLoader, etc, can be located
+                        // with greater accuracy. Directories can be skipped
+                        // since each file will be added explicitly.
+                        addExplicit(fileName, currentJar);
+                    }
                 }
             }
+
             zrf.close();
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/Basic.java	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6887710
+ * @summary Verify the impact of sun.misc.JarIndex.metaInfFilenames on Service loaders
+ * @run main/othervm Basic
+ */
+
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
+/**
+ * Verifies the impact of sun.misc.JarIndex.metaInfFilenames on service loaders
+ * (sun.misc.Service & java.util.ServiceLoader), as well as finding resources
+ * through Class.getResouce.
+ *
+ * 1) Compile the test sources:
+ *   jarA:
+ *     META-INF/services/my.happy.land
+ *     com/message/spi/MessageService.java
+ *     a/A.java
+ *   jarB:
+ *     META-INF/JAVA2.DS
+ *     META-INF/services/no.name.service
+ *     b/B.java
+ *   jarC:
+ *     META-INF/fonts.mf
+ *     META-INF/fonts/Company-corporate.ttf
+ *     META-INF/fonts/kidpr.ttf
+ *     META-INF/services/com.message.spi.MessageService
+ *     my/impl/StandardMessageService.java
+ *
+ * 2) Build three jar files a.jar, b.jar, c.jar
+ *
+ * 3) Create an index in a.jar (jar -i a.jar b.jar c.jar)
+ *      with sun.misc.JarIndex.metaInfFilenames=true
+ *
+ * 4) Start a HTTP server serving out the three jars.
+ *
+ * The test then tries to locate services/resources within the jars using
+ * URLClassLoader. Each request to the HTTP server is recorded to ensure
+ * only the correct amount of requests are being made.
+ *
+ * Note: Needs jdk/lib/tools.jar in the classpath to compile and run.
+ */
+
+public class Basic {
+    static final String slash = File.separator;
+    static final String[] testSources =  {
+         "jarA" + slash + "a" + slash + "A.java",
+         "jarA" + slash + "com" + slash + "message" + slash + "spi" + slash + "MessageService.java",
+         "jarB" + slash + "b" + slash + "B.java",
+         "jarC" + slash + "my" + slash + "impl" + slash + "StandardMessageService.java"};
+
+    static final String testSrc = System.getProperty("test.src");
+    static final String testSrcDir = testSrc != null ? testSrc : ".";
+    static final String testClasses = System.getProperty("test.classes");
+    static final String testClassesDir = testClasses != null ? testClasses : ".";
+
+    static JarHttpServer httpServer;
+
+    public static void main(String[] args) throws Exception {
+
+        // Set global url cache to false so that we can track every jar request.
+        (new URL("http://localhost/")).openConnection().setDefaultUseCaches(false);
+
+        buildTest();
+
+        try {
+            httpServer = new JarHttpServer(testClassesDir);
+            httpServer.start();
+
+            doTest(httpServer.getAddress());
+
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        } finally {
+            if (httpServer != null) { httpServer.stop(2); }
+        }
+    }
+
+    static void buildTest() {
+        /* compile the source that will be used to generate the jars */
+        for (int i=0; i<testSources.length; i++)
+            testSources[i] = testSrcDir + slash + testSources[i];
+
+        compile("-d" , testClassesDir,
+                "-sourcepath", testSrcDir,
+                testSources[0], testSources[1], testSources[2], testSources[3]);
+
+        /* build the 3 jar files */
+        jar("-cf", testClassesDir + slash + "a.jar",
+            "-C", testClassesDir, "a",
+            "-C", testClassesDir, "com",
+            "-C", testSrcDir + slash + "jarA", "META-INF");
+        jar("-cf", testClassesDir + slash + "b.jar",
+            "-C", testClassesDir, "b",
+            "-C", testSrcDir + slash + "jarB", "META-INF");
+        jar("-cf", testClassesDir + slash + "c.jar",
+            "-C", testClassesDir, "my",
+            "-C", testSrcDir + slash + "jarC", "META-INF");
+
+        /* Create an index in a.jar for b.jar and c.jar */
+        createIndex(testClassesDir);
+    }
+
+    /* run jar <args> */
+    static void jar(String... args) {
+        debug("Running: jar " + Arrays.toString(args));
+        sun.tools.jar.Main jar = new sun.tools.jar.Main(System.out, System.err, "jar");
+        if (!jar.run(args)) {
+            throw new RuntimeException("jar failed: args=" + Arrays.toString(args));
+        }
+    }
+
+    /* run javac <args> */
+    static void compile(String... args) {
+        debug("Running: javac " + Arrays.toString(args));
+        com.sun.tools.javac.main.Main compiler = new com.sun.tools.javac.main.Main("javac");
+        if (compiler.compile(args) != 0) {
+             throw new RuntimeException("javac failed: args=" + Arrays.toString(args));
+        }
+    }
+
+    static String jar;
+    static {
+        String javaHome = System.getProperty("java.home");
+        if (javaHome.endsWith("jre")) {
+            int index = javaHome.lastIndexOf(slash);
+            if (index != -1)
+                javaHome = javaHome.substring(0, index);
+        }
+
+        jar = javaHome + slash+  "bin" + slash + "jar";
+    }
+
+    /* create the index */
+    static void createIndex(String workingDir) {
+        // ProcessBuilder is used so that the current directory can be set
+        // to the directory that directly contains the jars.
+        debug("Running jar to create the index");
+        ProcessBuilder pb = new ProcessBuilder(
+           jar, "-J-Dsun.misc.JarIndex.metaInfFilenames=true", "-i", "a.jar", "b.jar", "c.jar");
+        pb.directory(new File(workingDir));
+        //pd.inheritIO();
+        try {
+            Process p = pb.start();
+            if(p.waitFor() != 0)
+                throw new RuntimeException("jar indexing failed");
+
+            if(debug && p != null) {
+                String line = null;
+                BufferedReader reader =
+                         new BufferedReader(new InputStreamReader(p.getInputStream()));
+                while((line = reader.readLine()) != null)
+                    debug(line);
+                reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
+                while((line = reader.readLine()) != null)
+                    debug(line);
+            }
+        } catch(InterruptedException ie) { throw new RuntimeException(ie);
+        } catch(IOException e) { throw new RuntimeException(e); }
+    }
+
+    static final boolean debug = true;
+
+    static void debug(Object message) { if (debug) System.out.println(message); }
+
+    /* service define in c.jar */
+    static final String messageService = "com.message.spi.MessageService";
+
+    /* a service that is not defined in any of the jars */
+    static final String unknownService = "java.lang.Object";
+
+    static void doTest(InetSocketAddress serverAddress) throws IOException {
+        URL baseURL = new URL("http://localhost:" + serverAddress.getPort() + "/");
+
+        int failed = 0;
+
+        // Tests using sun.misc.Service
+        if (!sunMiscServiceTest(baseURL, messageService, true, false, true)) {
+            System.out.println("Test: sun.misc.Service looking for " + messageService + ", failed");
+            failed++;
+        }
+        if (!sunMiscServiceTest(baseURL, unknownService, false, false, false)) {
+            System.out.println("Test: sun.misc.Service looking for " + unknownService + " failed");
+            failed++;
+        }
+
+        // Tests using java.util.SerivceLoader
+        if (!javaUtilServiceLoaderTest(baseURL, messageService, true, false, true)) {
+            System.out.println("Test: sun.misc.Service looking for " + messageService + ", failed");
+            failed++;
+        }
+        if (!javaUtilServiceLoaderTest(baseURL, unknownService, false, false, false)) {
+            System.out.println("Test: sun.misc.Service looking for " + unknownService + " failed");
+            failed++;
+        }
+
+        // Tests using java.lang.Class (similar to the FontManager in javafx)
+        if (!klassLoader(baseURL, "/META-INF/fonts.mf", true, false, true)) {
+            System.out.println("Test: klassLoader looking for /META-INF/fonts.mf failed");
+            failed++;
+        }
+        if (!klassLoader(baseURL, "/META-INF/unknown.mf", false, false, false)) {
+            System.out.println("Test: klassLoader looking for /META-INF/unknown.mf failed");
+            failed++;
+        }
+
+        if (failed > 0)
+            throw new RuntimeException("Failed: " + failed + " tests");
+    }
+
+    static boolean sunMiscServiceTest(URL baseURL,
+                                      String serviceClass,
+                                      boolean expectToFind,
+                                      boolean expectbDotJar,
+                                      boolean expectcDotJar) throws IOException {
+        debug("----------------------------------");
+        debug("Running test with sun.misc.Service looking for " + serviceClass);
+        URLClassLoader loader = getLoader(baseURL);
+        httpServer.reset();
+
+        Class messageServiceClass = null;
+        try {
+            messageServiceClass = loader.loadClass(serviceClass);
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println(cnfe);
+            throw new RuntimeException("Error in test: " + cnfe);
+        }
+
+        Iterator<Class<?>> iterator = sun.misc.Service.providers(messageServiceClass, loader);
+        if (expectToFind && !iterator.hasNext()) {
+            debug(messageServiceClass + " NOT found.");
+            return false;
+        }
+
+        while (iterator.hasNext()) {
+            debug("found " + iterator.next() + " " + messageService);
+        }
+
+        debug("HttpServer: " + httpServer);
+
+        if (!expectbDotJar && httpServer.bDotJar > 0) {
+            debug("Unexpeced request sent to the httpserver for b.jar");
+            return false;
+        }
+        if (!expectcDotJar && httpServer.cDotJar > 0) {
+            debug("Unexpeced request sent to the httpserver for c.jar");
+            return false;
+        }
+
+        return true;
+    }
+
+    static boolean javaUtilServiceLoaderTest(URL baseURL,
+                                             String serviceClass,
+                                             boolean expectToFind,
+                                             boolean expectbDotJar,
+                                             boolean expectcDotJar) throws IOException {
+        debug("----------------------------------");
+        debug("Running test with java.util.ServiceLoader looking for " + serviceClass);
+        URLClassLoader loader = getLoader(baseURL);
+        httpServer.reset();
+
+        Class messageServiceClass = null;
+        try {
+            messageServiceClass = loader.loadClass(serviceClass);
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println(cnfe);
+            throw new RuntimeException("Error in test: " + cnfe);
+        }
+
+        Iterator<Class<?>> iterator = (ServiceLoader.load(messageServiceClass, loader)).iterator();
+        if (expectToFind && !iterator.hasNext()) {
+            debug(messageServiceClass + " NOT found.");
+            return false;
+        }
+
+        while (iterator.hasNext()) {
+            debug("found " + iterator.next() + " " + messageService);
+        }
+
+        debug("HttpServer: " + httpServer);
+
+        if (!expectbDotJar && httpServer.bDotJar > 0) {
+            debug("Unexpeced request sent to the httpserver for b.jar");
+            return false;
+        }
+        if (!expectcDotJar && httpServer.cDotJar > 0) {
+            debug("Unexpeced request sent to the httpserver for c.jar");
+            return false;
+        }
+
+        return true;
+    }
+
+    /* Tries to find a resource in a similar way to the font manager in javafx
+     * com.sun.javafx.scene.text.FontManager */
+    static boolean klassLoader(URL baseURL,
+                               String resource,
+                               boolean expectToFind,
+                               boolean expectbDotJar,
+                               boolean expectcDotJar) throws IOException {
+        debug("----------------------------------");
+        debug("Running test looking for " + resource);
+        URLClassLoader loader = getLoader(baseURL);
+        httpServer.reset();
+
+        Class ADotAKlass = null;
+        try {
+            ADotAKlass = loader.loadClass("a.A");
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println(cnfe);
+            throw new RuntimeException("Error in test: " + cnfe);
+        }
+
+        URL u = ADotAKlass.getResource(resource);
+        if (expectToFind && u == null) {
+            System.out.println("Expected to find " + resource + " but didn't");
+            return false;
+        }
+
+        debug("HttpServer: " + httpServer);
+
+        if (!expectbDotJar && httpServer.bDotJar > 0) {
+            debug("Unexpeced request sent to the httpserver for b.jar");
+            return false;
+        }
+        if (!expectcDotJar && httpServer.cDotJar > 0) {
+            debug("Unexpeced request sent to the httpserver for c.jar");
+            return false;
+        }
+
+        return true;
+    }
+
+    static URLClassLoader getLoader(URL baseURL) throws IOException {
+        ClassLoader loader = Basic.class.getClassLoader();
+
+        while (loader.getParent() != null)
+            loader = loader.getParent();
+
+        return new URLClassLoader( new URL[]{
+            new URL(baseURL, "a.jar"),
+            new URL(baseURL, "b.jar"),
+            new URL(baseURL, "c.jar")}, loader );
+    }
+
+    /**
+     * HTTP Server to server the jar files.
+     */
+    static class JarHttpServer implements HttpHandler {
+        final String docsDir;
+        final HttpServer httpServer;
+        int aDotJar, bDotJar, cDotJar;
+
+        JarHttpServer(String docsDir) throws IOException {
+            this.docsDir = docsDir;
+
+            httpServer = HttpServer.create(new InetSocketAddress(0), 0);
+            httpServer.createContext("/", this);
+        }
+
+        void start() throws IOException {
+            httpServer.start();
+        }
+
+        void stop(int delay) {
+            httpServer.stop(delay);
+        }
+
+        InetSocketAddress getAddress() {
+            return httpServer.getAddress();
+        }
+
+        void reset() {
+            aDotJar = bDotJar = cDotJar = 0;
+        }
+
+        @Override
+        public String toString() {
+            return "aDotJar=" + aDotJar + ", bDotJar=" + bDotJar + ", cDotJar=" + cDotJar;
+        }
+
+        public void handle(HttpExchange t) throws IOException {
+            InputStream is = t.getRequestBody();
+            Headers map = t.getRequestHeaders();
+            Headers rmap = t.getResponseHeaders();
+            URI uri = t.getRequestURI();
+
+            debug("Server: received request for " + uri);
+            String path = uri.getPath();
+            if (path.endsWith("a.jar"))
+                aDotJar++;
+            else if (path.endsWith("b.jar"))
+                bDotJar++;
+            else if (path.endsWith("c.jar"))
+                cDotJar++;
+            else
+                System.out.println("Unexpected resource request" + path);
+
+            while (is.read() != -1);
+            is.close();
+
+            File file = new File(docsDir, path);
+            if (!file.exists())
+                throw new RuntimeException("Error: request for " + file);
+            long clen = file.length();
+            t.sendResponseHeaders (200, clen);
+            OutputStream os = t.getResponseBody();
+            FileInputStream fis = new FileInputStream(file);
+            try {
+                byte[] buf = new byte [16 * 1024];
+                int len;
+                while ((len=fis.read(buf)) != -1) {
+                    os.write (buf, 0, len);
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            fis.close();
+            os.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarA/META-INF/services/my.happy.land	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,23 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+ 
+# The contents of this file do not matter. It exists
+# simply to have a service defined in META-INF/services.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarA/a/A.java	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package a;
+
+public class A {
+    public static void hello() throws Exception {
+        System.out.println("Hello from a.A");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarA/com/message/spi/MessageService.java	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.message.spi;
+
+public interface MessageService {
+    String message();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarB/META-INF/JAVA2.DS	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,23 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+# The contents of this file do not matter. It exists
+# simply to have a file under META-INF.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarB/META-INF/services/no.name.service	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,23 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+# The contents of this file do not matter. It exists
+# simply to have a service defined in META-INF/services.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarB/b/B.java	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package b;
+
+public class B {
+    public static void hello() {
+        System.out.println("Hello from b.B");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarC/META-INF/fonts.mf	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,23 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+corporate=/fonts/Company-corporate.ttf
+crazy-looking=/fonts/kidpr.ttf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarC/META-INF/fonts/Company-corporate.ttf	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,22 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+This is not a real font.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarC/META-INF/fonts/kidpr.ttf	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,22 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+This is not a real font.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarC/META-INF/services/com.message.spi.MessageService	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,22 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+my.impl.StandardMessageService
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/misc/JarIndex/metaInfFilenames/jarC/my/impl/StandardMessageService.java	Thu Feb 03 11:56:56 2011 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package my.impl;
+
+public class StandardMessageService implements com.message.spi.MessageService {
+    @Override
+    public String message() {
+        return "This is a message from the standard message service";
+    }
+}