1 /*
   2  * Copyright (c) 2016, 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 
  25 // Structure of the test:
  26 // TransformRelatedClassesAppCDS -- common main test driver
  27 // Invoked from test driver classes:
  28 //     TransformInterfaceAndImplementor, TransformSuperAndSubClasses.java
  29 //     prepares test artifacts, launches tests, checks results
  30 // SuperClazz, SubClass -- classes under test
  31 // Interface, Implementor -- classes under test
  32 // TransformerAgent -- an agent that is used when JVM-under-test is executed
  33 //     to transform specific strings inside specified classes
  34 // TransformerAgent.mf - accompanies transformer agent
  35 // CustomLoaderApp -- a test "application" that is used to load
  36 //     classes-under-test (Parent, Child) via custom class loader, using
  37 //     AppCDS-v2 mechanism (unregistered custom loaders, aka FP)
  38 //     This "app" is launched in a child process by this driver with sharing on.
  39 
  40 import java.io.File;
  41 import java.util.ArrayList;
  42 import jdk.test.lib.Platform;
  43 import jdk.test.lib.process.OutputAnalyzer;
  44 
  45 // This class is intended to test 2 parent-child relationships:
  46 // 1. Base Class (parent) and Derived Class (child)
  47 // 2. Interface (parent) and Implementor (child)
  48 //    Parameters to main(): parent, child
  49 
  50 public class TransformRelatedClassesAppCDS extends TransformRelatedClasses {
  51     private static void log(String msg, Object... args) {
  52         String msg0 = String.format(msg, args);
  53         System.out.println("TransformRelatedClassesAppCDS: " + msg0);
  54     }
  55 
  56     // Initial Test Matrix:
  57     // (ParentTransformed = true/false, ChildTransformed = true/false) x
  58     // (BootCDS - see open tests, AppCDS-v1, AppCDS-v2-unregistered)
  59     // Total cases: 2 x 4 = 8
  60     public static void main(String args[]) throws Exception {
  61         TransformRelatedClassesAppCDS test =
  62             new TransformRelatedClassesAppCDS(args[0], args[1]);
  63 
  64         test.prepareAgent(agentClasses);
  65 
  66         // Test Table
  67         // testCaseId |  transformParent | tranformChild | isParentExpectedShared | isChildExpectedShared
  68         ArrayList<TestEntry> testTable = new ArrayList<>();
  69 
  70         // base case - no tranformation - all expected to be shared
  71         testTable.add(new TestEntry(0, false, false, true, true));
  72 
  73         // transform parent only - both parent and child should not be shared
  74         testTable.add(new TestEntry(1, true, false, false, false));
  75 
  76         // transform parent and child - both parent and child should not be shared
  77         testTable.add(new TestEntry(2, true, true, false, false));
  78 
  79         // transform child only - parent should still be shared, but not child
  80         testTable.add(new TestEntry(3, false, true, true, false));
  81 
  82         // run the tests
  83         test.runWithAppLoader(testTable);
  84         test.runWithCustomLoader(testTable);
  85     }
  86 
  87 
  88     public TransformRelatedClassesAppCDS(String parent, String child) {
  89         super(parent, child);
  90 
  91         // a trick to get it compiled by jtreg
  92         CustomLoaderApp.ping();
  93     }
  94 
  95 
  96     private void prepareAgent(String[] agentClasses) throws Exception {
  97         String manifest = "../../../../testlibrary/jvmti/TransformerAgent.mf";
  98         agentJar = ClassFileInstaller.writeJar("TransformerAgent.jar",
  99                    ClassFileInstaller.Manifest.fromSourceFile(manifest),
 100                                            agentClasses);
 101     }
 102 
 103 
 104     private void runWithAppLoader(ArrayList<TestEntry> testTable) throws Exception {
 105         String appJar = writeJar("app", testClasses);
 106 
 107         // create an archive
 108         OutputAnalyzer out = TestCommon.dump(appJar, testClasses);
 109         TestCommon.checkDump(out);
 110 
 111         // execute with archive
 112         for (TestEntry entry : testTable) {
 113             log("runTestWithAppLoader(): testCaseId = %d", entry.testCaseId);
 114             String params = TransformTestCommon.getAgentParams(entry, parent, child);
 115             String agentParam = String.format("-javaagent:%s=%s", agentJar, params);
 116             TestCommon.run("-Xlog:class+load=info", "-cp", appJar,
 117                            agentParam, child)
 118               .assertNormalExit(output -> TransformTestCommon.checkResults(entry, output, parent, child));
 119         }
 120     }
 121 
 122 
 123     private String[] getCustomClassList(String loaderType, String customJar) {
 124         String type = child + "-" + loaderType;
 125 
 126         switch (type) {
 127 
 128         case "SubClass-unregistered":
 129             return new String[] {
 130                 "CustomLoaderApp",
 131                 "java/lang/Object id: 0",
 132                 parent + " id: 1 super: 0 source: " + customJar,
 133                 child +  " id: 2 super: 1 source: " + customJar,
 134             };
 135 
 136         case "Implementor-unregistered":
 137             return new String[] {
 138                 "CustomLoaderApp",
 139                 "java/lang/Object id: 0",
 140                 parent + " id: 1 super: 0 source: " + customJar,
 141                 child +  " id: 2 super: 0 interfaces: 1 source: " + customJar,
 142             };
 143 
 144         default:
 145             throw new IllegalArgumentException("getCustomClassList - wrong type: " + type);
 146         }
 147     }
 148 
 149 
 150     private void runWithCustomLoader(ArrayList<TestEntry> testTable) throws Exception {
 151         if (!Platform.areCustomLoadersSupportedForCDS()) {
 152             log("custom loader not supported for this platform" +
 153                 " - skipping test case for custom loader");
 154             return;
 155         }
 156 
 157         if (TestCommon.isDynamicArchive()) {
 158             log("custom loader class list not applicable to dynamic archive" +
 159                 " - skipping test case for custom loader");
 160             return;
 161         }
 162 
 163         String appClasses[] = {
 164             "CustomLoaderApp",
 165         };
 166 
 167         String customClasses[] = { parent, child };
 168 
 169         // create jar files: appJar, customJar (for custom loaders to load classes from)
 170         String appJar = writeJar("custldr-app", appClasses);
 171         String customJar = writeJar("custldr-custom", customClasses);
 172 
 173         for (TestEntry entry : testTable) {
 174             log("runTestWithCustomLoader(): testCaseId = %d", entry.testCaseId);
 175             // unregistered (aka FP) case
 176             String[] classList = getCustomClassList("unregistered",customJar);
 177             execAndCheckWithCustomLoader(entry, "unregistered", classList,
 178                                          appJar, agentJar, customJar);
 179         }
 180     }
 181 
 182 
 183     private void
 184         execAndCheckWithCustomLoader(TestEntry entry, String loaderType,
 185                                      String[] classList, String appJar,
 186                                      String agentJar, String customJar)
 187         throws Exception {
 188 
 189         OutputAnalyzer out = TestCommon.dump(appJar, classList);
 190         TestCommon.checkDump(out);
 191 
 192         String agentParam = "-javaagent:" + agentJar + "=" +
 193             TransformTestCommon.getAgentParams(entry, parent, child);
 194 
 195         TestCommon.run("-Xlog:class+load=info",
 196                        "-cp", appJar,
 197                        agentParam,
 198                        "CustomLoaderApp",
 199                        customJar, loaderType, child)
 200           .assertNormalExit(output -> TransformTestCommon.checkResults(entry, output, parent, child));
 201     }
 202 
 203 
 204     private String writeJar(String type, String[] classes)
 205         throws Exception {
 206         String jarName = String.format("%s-%s.jar", child, type);
 207         return ClassFileInstaller.writeJar(jarName, classes);
 208     }
 209 }