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 plugins
  28  * @author Andrei Eremeev
  29  * @modules jdk.jlink/jdk.tools.jlink.internal
  30  *          jdk.jlink/jdk.tools.jlink.internal.plugins.asm
  31  * @run main PackageMappingTest
  32  */
  33 import java.io.IOException;
  34 import java.nio.ByteBuffer;
  35 import java.util.ArrayList;
  36 import java.util.Arrays;
  37 import java.util.HashMap;
  38 import java.util.HashSet;
  39 import java.util.List;
  40 import java.util.Map;
  41 import java.util.Objects;
  42 import java.util.Set;
  43 import java.util.function.Function;
  44 import java.util.stream.Collectors;
  45 
  46 import jdk.tools.jlink.internal.plugins.asm.AsmGlobalPool;
  47 import jdk.tools.jlink.internal.plugins.asm.AsmModulePool;
  48 import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile;
  49 import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableResourcePool;
  50 import jdk.tools.jlink.plugin.PluginException;
  51 import jdk.tools.jlink.plugin.ModuleEntry;
  52 import jdk.tools.jlink.plugin.ModulePool;
  53 
  54 public class PackageMappingTest extends AsmPluginTestBase {
  55 
  56     private final List<String> newFiles = Arrays.asList(
  57             "/java.base/a1/bbb/c",
  58             "/" + TEST_MODULE + "/a2/bbb/d"
  59     );
  60 
  61     public static void main(String[] args) throws Exception {
  62         if (!isImageBuild()) {
  63             System.err.println("Test not run. Not image build.");
  64             return;
  65         }
  66         new PackageMappingTest().test();
  67     }
  68 
  69     public void test() throws Exception {
  70         TestPlugin[] plugins = new TestPlugin[]{
  71             new PackageMappingPlugin(newFiles, false),
  72             new PackageMappingPlugin(newFiles, true)
  73         };
  74         for (TestPlugin p : plugins) {
  75             ModulePool pool = p.visit(getPool());
  76             p.test(getPool(), pool);
  77         }
  78     }
  79 
  80     public class PackageMappingPlugin extends TestPlugin {
  81 
  82         private final Map<String, List<ResourceFile>> newFiles;
  83         private final boolean testGlobal;
  84 
  85         private String getModuleName(String res) {
  86             return res.substring(1, res.indexOf("/", 1));
  87         }
  88 
  89         private PackageMappingPlugin(List<String> files, boolean testGlobal) {
  90             this.newFiles = new HashMap<>();
  91             this.testGlobal = testGlobal;
  92             for (String file : files) {
  93                 String moduleName = getModuleName(file);
  94                 String path = file.substring(1 + moduleName.length() + 1);
  95                 newFiles.computeIfAbsent(moduleName, $ -> new ArrayList<>()).add(
  96                         new ResourceFile(path, new byte[0]));
  97             }
  98         }
  99 
 100         @Override
 101         public void visit() {
 102             testMapToUnknownModule();
 103             testMapPackageTwice();
 104             testPackageMapping();
 105         }
 106 
 107         @Override
 108         public void test(ModulePool inResources, ModulePool outResources) {
 109             Set<String> in = getPools().getGlobalPool().getResourceFiles().stream()
 110                     .map(ModuleEntry::getPath)
 111                     .collect(Collectors.toSet());
 112             Set<String> out = extractResources(outResources).stream()
 113                     .map(ModuleEntry::getPath)
 114                     .collect(Collectors.toSet());
 115             in.addAll(PackageMappingTest.this.newFiles);
 116             if (!Objects.equals(in, out)) {
 117                 throw new AssertionError("Expected: " + in + ", got: " + outResources);
 118             }
 119         }
 120 
 121         private void testPackageMapping() {
 122             AsmGlobalPool globalPool = getPools().getGlobalPool();
 123             try {
 124                 Map<String, Set<String>> mappedPackages = new HashMap<>();
 125                 Function<String, Set<String>> produceSet = $ -> new HashSet<>();
 126                 for (Map.Entry<String, List<ResourceFile>> entry : newFiles.entrySet()) {
 127                     String moduleName = entry.getKey();
 128                     Set<String> module = mappedPackages.computeIfAbsent(moduleName, produceSet);
 129                     AsmModulePool modulePool = getPools().getModulePool(moduleName);
 130                     for (ResourceFile r : entry.getValue()) {
 131                         String name = r.getPath();
 132                         String packageName = name.substring(0, name.lastIndexOf('/'));
 133                         if (module.add(packageName)) {
 134                             globalPool.addPackageModuleMapping(packageName, moduleName);
 135                         }
 136                         WritableResourcePool transformedResourceFiles = testGlobal
 137                                 ? globalPool.getTransformedResourceFiles()
 138                                 : modulePool.getTransformedResourceFiles();
 139                         transformedResourceFiles.addResourceFile(r);
 140                     }
 141                     try {
 142                         modulePool.getTransformedResourceFiles().addResourceFile(
 143                                 new ResourceFile("a3/bbb", new byte[0]));
 144                         throw new AssertionError("Exception expected");
 145                     } catch (Exception ex) {
 146                         // expected
 147                     }
 148                 }
 149                 try {
 150                     globalPool.getTransformedResourceFiles().addResourceFile(
 151                             new ResourceFile("a3/bbb", new byte[0]));
 152                     throw new AssertionError("Exception expected");
 153                 } catch (Exception ex) {
 154                     // expected
 155                 }
 156             } catch (Exception e) {
 157                 throw new RuntimeException(e);
 158             }
 159         }
 160 
 161         private void testMapPackageTwice() {
 162             try {
 163                 AsmGlobalPool globalPool = getPools().getGlobalPool();
 164                 globalPool.addPackageModuleMapping("a/p1", TEST_MODULE);
 165                 globalPool.addPackageModuleMapping("a/p1", TEST_MODULE);
 166                 throw new AssertionError("Exception expected after mapping a package twice to the same module");
 167             } catch (Exception e) {
 168                 if (e instanceof PluginException) {
 169                     // expected
 170                     String message = e.getMessage();
 171                     if (!(TEST_MODULE + " module already contains package a.p1").equals(message)) {
 172                         throw new AssertionError(e);
 173                     }
 174                 } else {
 175                     throw new AssertionError(e);
 176                 }
 177             }
 178         }
 179 
 180         private void testMapToUnknownModule() {
 181             AsmModulePool unknownModule = getPools().getModulePool("UNKNOWN");
 182             if (unknownModule != null) {
 183                 throw new AssertionError("getModulePool returned not null value: " + unknownModule.getModuleName());
 184             }
 185             try {
 186                 AsmGlobalPool globalPool = getPools().getGlobalPool();
 187                 globalPool.addPackageModuleMapping("a/b", "UNKNOWN");
 188                 throw new AssertionError("Exception expected after mapping a package to unknown module");
 189             } catch (Exception e) {
 190                 String message = e.getMessage();
 191                 if (message == null || !message.startsWith("Unknown module UNKNOWN")) {
 192                     throw new AssertionError(e);
 193                 }
 194             }
 195         }
 196     }
 197 }