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