1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.File;
  25 import java.net.URL;
  26 import java.net.URLClassLoader;
  27 import java.nio.file.Path;
  28 import java.nio.file.Paths;
  29 import java.util.jar.Attributes;
  30 import java.util.jar.Manifest;
  31 import jdk.test.lib.util.JarUtils;
  32 import jdk.test.lib.compiler.InMemoryJavaCompiler;
  33 
  34 /*
  35  * @test
  36  * @bug 8216401
  37  * @summary Test loading of JAR Class-Path entry with file: scheme
  38  * @library /test/lib
  39  *
  40  * @run main/othervm JarClassPathFileEntry
  41  * @run main/othervm -Djdk.net.URLClassPath.disableClassPathURLCheck=true JarClassPathFileEntry
  42  * @run main/othervm -Djdk.net.URLClassPath.disableClassPathURLCheck=false JarClassPathFileEntry
  43  */
  44 
  45 public class JarClassPathFileEntry {
  46     private final static boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows");
  47 
  48     private final static String TEST_CLASSES = System.getProperty("test.classes");
  49     private final static String OTHER_DIR = TEST_CLASSES + "/OTHER/";
  50     
  51     private final static Path OTHER_JAR_PATH = Paths.get(OTHER_DIR, "Other.jar");    
  52     private final static Path CONTEXT_JAR_PATH = Paths.get(TEST_CLASSES, "Context.jar");
  53     
  54     public static void main(String[] args) throws Throwable {
  55         // Create Other.class in OTHER_DIR, off the default classpath
  56         byte klassbuf[] = InMemoryJavaCompiler.compile("Other",
  57                                                        "public class Other {}");
  58         ClassFileInstaller.writeClassToDisk("Other", klassbuf, OTHER_DIR);
  59         
  60         // Create Other.jar in OTHER_DIR
  61         JarUtils.createJarFile(OTHER_JAR_PATH,
  62                                Paths.get(OTHER_DIR),
  63                                Paths.get(OTHER_DIR, "Other.class"));            
  64 
  65         // Create Context.class
  66         klassbuf = InMemoryJavaCompiler.compile("Context",
  67                                                 "public class Context {}");
  68         ClassFileInstaller.writeClassToDisk("Context", klassbuf, TEST_CLASSES);
  69 
  70         // Create Context.jar w/ "file:" entry for Other.jar            
  71         Manifest mf = new Manifest();
  72         Attributes attrs = mf.getMainAttributes();
  73         attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
  74                 
  75         String classPathEntry = "file:" + (IS_WINDOWS ? toUnixPath(OTHER_JAR_PATH.toString())
  76                                                       :            OTHER_JAR_PATH.toString());
  77         attrs.put(Attributes.Name.CLASS_PATH, classPathEntry);
  78         
  79         System.out.println("Creating Context.jar with Class-Path: " + classPathEntry);
  80         JarUtils.createJarFile(CONTEXT_JAR_PATH, mf,
  81                                Paths.get(TEST_CLASSES),
  82                                Paths.get(TEST_CLASSES, "Context.class"));
  83 
  84         // Use URLClassLoader w/ Context.jar to load Other.class, which will
  85         // load via the Class-Path entry
  86         URL url = CONTEXT_JAR_PATH.toUri().toURL();            
  87         URLClassLoader ucl = new URLClassLoader("TestURLClassLoader",
  88                                                 new URL[]{ url },
  89                                                 null); // don't delegate to App CL
  90         Class<?> otherClass = Class.forName("Other", true, ucl); // ClassNotFoundException -> fail                                               
  91         System.out.println("Loaded: " + otherClass);            
  92     }
  93     
  94     /* Convert a Windows path to a unix-style path, and remove any drive letter */
  95     private static String toUnixPath(String orig) {
  96         String retVal = new File(orig).toURI().getPath();
  97         int colonAt = retVal.indexOf(':');
  98 
  99         if (colonAt != -1 && colonAt < 3) {
 100             retVal = retVal.substring(colonAt + 1); // Start after the drive letter
 101         }
 102         return retVal;
 103     }
 104 }