1 /* 2 * Copyright (c) 2015, 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 * Asm plugin testing. 26 * @test 27 * @summary Test visitors. 28 * @author Andrei Eremeev 29 * @modules java.base/jdk.internal.org.objectweb.asm 30 * jdk.jlink/jdk.tools.jlink.internal 31 * jdk.jlink/jdk.tools.jlink.internal.plugins.asm 32 * @build AsmPluginTestBase 33 * @run main VisitorTest 34 */ 35 36 import java.io.IOException; 37 import java.util.Collection; 38 import java.util.function.Function; 39 40 import jdk.internal.org.objectweb.asm.ClassReader; 41 import jdk.internal.org.objectweb.asm.ClassVisitor; 42 import jdk.internal.org.objectweb.asm.ClassWriter; 43 import jdk.internal.org.objectweb.asm.Opcodes; 44 import jdk.tools.jlink.internal.plugins.asm.AsmPool; 45 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ClassReaderVisitor; 46 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile; 47 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFileVisitor; 48 import jdk.tools.jlink.internal.plugins.asm.AsmPools; 49 import jdk.tools.jlink.plugin.ModuleEntry; 50 import jdk.tools.jlink.plugin.ModulePool; 51 52 public class VisitorTest extends AsmPluginTestBase { 53 54 public static void main(String[] args) throws Exception { 55 if (!isImageBuild()) { 56 System.err.println("Test not run. Not image build."); 57 return; 58 } 59 new VisitorTest().test(); 60 } 61 62 @Override 63 public void test() throws Exception { 64 TestPlugin[] plugins = new TestPlugin[] { 65 new ClassVisitorPlugin("Class-global-pool", AsmPools::getGlobalPool), 66 new ClassVisitorPlugin("Class-module-pool", pools -> pools.getModulePool("java.base")), 67 new ResourceVisitorPlugin("Resource-global-pool", AsmPools::getGlobalPool), 68 new ResourceVisitorPlugin("Resource-module-pool", pools -> pools.getModulePool("java.base")) 69 }; 70 for (TestPlugin p : plugins) { 71 System.err.println("Testing: " + p.getName()); 72 ModulePool out = p.visit(getPool()); 73 p.test(getPool(), out); 74 } 75 } 76 77 private static class CustomClassReaderVisitor implements ClassReaderVisitor { 78 private int amount = 0; 79 private int changed = 0; 80 81 @Override 82 public ClassWriter visit(ClassReader reader) { 83 if ((amount++ % 2) == 0) { 84 String className = reader.getClassName(); 85 if (className.endsWith("module-info")) { 86 return null; 87 } 88 ClassWriter cw = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); 89 reader.accept(new ClassVisitor(Opcodes.ASM5, cw) { 90 @Override 91 public void visit(int i, int i1, String s, String s1, String s2, String[] strings) { 92 super.visit(i, i1, s + "Changed", s1, s2, strings); 93 } 94 }, ClassReader.EXPAND_FRAMES); 95 ++changed; 96 return cw; 97 } else { 98 return null; 99 } 100 } 101 102 public int getAmount() { 103 return amount; 104 } 105 106 public int getNumberOfChanged() { 107 return changed; 108 } 109 } 110 111 private static class CustomResourceFileVisitor implements ResourceFileVisitor { 112 private int amount = 0; 113 private int changed = 0; 114 115 @Override 116 public ResourceFile visit(ResourceFile resourceFile) { 117 if ((amount++ % 2) == 0) { 118 ++changed; 119 return new ResourceFile(resourceFile.getPath() + "Changed", resourceFile.getContent()); 120 } else { 121 return null; 122 } 123 } 124 125 public int getAmount() { 126 return amount; 127 } 128 129 public int getNumberOfChanged() { 130 return changed; 131 } 132 } 133 134 public class ClassVisitorPlugin extends TestPlugin { 135 136 private final String name; 137 private final Function<AsmPools, AsmPool> getPool; 138 private final CustomClassReaderVisitor classReaderVisitor = new CustomClassReaderVisitor(); 139 140 public ClassVisitorPlugin(String name, Function<AsmPools, AsmPool> getPool) { 141 this.name = name; 142 this.getPool = getPool; 143 } 144 145 @Override 146 public void visit() { 147 AsmPool pool = getPool.apply(getPools()); 148 pool.visitClassReaders(classReaderVisitor); 149 } 150 151 @Override 152 public void test(ModulePool in, ModulePool out) throws Exception { 153 Collection<ModuleEntry> inClasses = getPool.apply(getPools()).getClasses(); 154 if (inClasses.size() != classReaderVisitor.getAmount()) { 155 throw new AssertionError("Testing " + name + ". Number of visited classes. Expected: " + 156 inClasses.size() + ", got: " + classReaderVisitor.getAmount()); 157 } 158 Collection<ModuleEntry> outClasses = extractClasses(out); 159 int changedClasses = 0; 160 for (ModuleEntry r : outClasses) { 161 if (r.getPath().endsWith("Changed.class")) { 162 ++changedClasses; 163 } 164 } 165 if (changedClasses != classReaderVisitor.getNumberOfChanged()) { 166 throw new AssertionError("Testing " + name + ". Changed classes. Expected: " + changedClasses + 167 ", got: " + classReaderVisitor.getNumberOfChanged()); 168 } 169 } 170 171 @Override 172 public String getName() { 173 return name; 174 } 175 } 176 177 public class ResourceVisitorPlugin extends TestPlugin { 178 179 private final String name; 180 private final Function<AsmPools, AsmPool> getPool; 181 private final CustomResourceFileVisitor resourceFileVisitor = new CustomResourceFileVisitor(); 182 183 public ResourceVisitorPlugin(String name, Function<AsmPools, AsmPool> getPool) { 184 this.name = name; 185 this.getPool = getPool; 186 } 187 188 @Override 189 public void visit() { 190 AsmPool pool = getPool.apply(getPools()); 191 pool.visitResourceFiles(resourceFileVisitor); 192 } 193 194 @Override 195 public void test(ModulePool in, ModulePool out) throws Exception { 196 Collection<ModuleEntry> inResources = getPool.apply(getPools()).getResourceFiles(); 197 if (inResources.size() != resourceFileVisitor.getAmount()) { 198 throw new AssertionError("Testing " + name + ". Number of visited resources. Expected: " + 199 inResources.size() + ", got: " + resourceFileVisitor.getAmount()); 200 } 201 Collection<ModuleEntry> outResources = extractResources(out); 202 int changedClasses = 0; 203 for (ModuleEntry r : outResources) { 204 if (r.getPath().endsWith("Changed")) { 205 ++changedClasses; 206 } 207 } 208 if (changedClasses != resourceFileVisitor.getNumberOfChanged()) { 209 throw new AssertionError("Testing " + name + ". Changed classes. Expected: " + changedClasses + 210 ", got: " + resourceFileVisitor.getNumberOfChanged()); 211 } 212 } 213 214 @Override 215 public String getName() { 216 return name; 217 } 218 } 219 }