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  * @test
  26  * @summary Test previsitor
  27  * @author Andrei Eremeev
  28  * @modules jdk.jlink/jdk.tools.jlink
  29  *          jdk.jlink/jdk.tools.jlink.internal
  30  *          jdk.jlink/jdk.tools.jlink.plugin
  31  * @run main/othervm PrevisitorTest
  32  */
  33 import java.nio.ByteOrder;
  34 import java.util.ArrayList;
  35 import java.util.Collection;
  36 import java.util.Collections;
  37 import java.util.HashMap;
  38 import java.util.List;
  39 import java.util.Map;
  40 import java.util.Optional;
  41 import java.util.stream.Collectors;
  42 
  43 import jdk.tools.jlink.internal.ImagePluginConfiguration;
  44 import jdk.tools.jlink.internal.Jlink;
  45 import jdk.tools.jlink.internal.PluginRepository;
  46 import jdk.tools.jlink.internal.ImagePluginStack;
  47 import jdk.tools.jlink.internal.ResourcePoolManager;
  48 import jdk.tools.jlink.internal.ResourcePoolManager.ResourcePoolImpl;
  49 import jdk.tools.jlink.internal.ResourcePrevisitor;
  50 import jdk.tools.jlink.internal.StringTable;
  51 import jdk.tools.jlink.plugin.Plugin;
  52 import jdk.tools.jlink.plugin.ResourcePool;
  53 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
  54 import jdk.tools.jlink.plugin.ResourcePoolEntry;
  55 
  56 public class PrevisitorTest {
  57 
  58     public static void main(String[] args) throws Exception {
  59         new PrevisitorTest().test();
  60     }
  61 
  62     private static Plugin createPlugin(String name) {
  63         return Jlink.newPlugin(name, Collections.emptyMap(), null);
  64     }
  65 
  66     public void test() throws Exception {
  67         CustomPlugin plugin = new CustomPlugin();
  68         PluginRepository.registerPlugin(plugin);
  69         List<Plugin> plugins = new ArrayList<>();
  70         plugins.add(createPlugin(CustomPlugin.NAME));
  71         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new Jlink.PluginsConfiguration(plugins,
  72                 null, null));
  73         ResourcePoolManager inResources = new ResourcePoolManager(ByteOrder.nativeOrder(), new CustomStringTable());
  74         inResources.add(ResourcePoolEntry.create("/aaa/bbb/res1.class", new byte[90]));
  75         inResources.add(ResourcePoolEntry.create("/aaa/bbb/res2.class", new byte[90]));
  76         inResources.add(ResourcePoolEntry.create("/aaa/bbb/res3.class", new byte[90]));
  77         inResources.add(ResourcePoolEntry.create("/aaa/ddd/res1.class", new byte[90]));
  78         inResources.add(ResourcePoolEntry.create("/aaa/res1.class", new byte[90]));
  79         ResourcePool outResources = stack.visitResources(inResources);
  80         Collection<String> input = inResources.entries()
  81                 .map(Object::toString)
  82                 .collect(Collectors.toList());
  83         Collection<String> output = outResources.entries()
  84                 .map(Object::toString)
  85                 .collect(Collectors.toList());
  86         if (!input.equals(output)) {
  87             throw new AssertionError("Input and output resources differ: input: "
  88                     + input + ", output: " + output);
  89         }
  90     }
  91 
  92     private static class CustomStringTable implements StringTable {
  93 
  94         private final List<String> strings = new ArrayList<>();
  95 
  96         @Override
  97         public int addString(String str) {
  98             strings.add(str);
  99             return strings.size() - 1;
 100         }
 101 
 102         @Override
 103         public String getString(int id) {
 104             return strings.get(id);
 105         }
 106 
 107         public int size() {
 108             return strings.size();
 109         }
 110     }
 111 
 112     private static class CustomPlugin implements Plugin, ResourcePrevisitor {
 113 
 114         private static String NAME = "plugin";
 115 
 116         private boolean isPrevisitCalled = false;
 117 
 118         @Override
 119         public ResourcePool transform(ResourcePool inResources, ResourcePoolBuilder outResources) {
 120             if (!isPrevisitCalled) {
 121                 throw new AssertionError("Previsit was not called");
 122             }
 123             CustomStringTable table = (CustomStringTable)((ResourcePoolImpl)inResources).getStringTable();
 124             if (table.size() == 0) {
 125                 throw new AssertionError("Table is empty");
 126             }
 127             Map<String, Integer> count = new HashMap<>();
 128             for (int i = 0; i < table.size(); ++i) {
 129                 String s = table.getString(i);
 130                 Optional<ResourcePoolEntry> e = inResources.findEntry(s);
 131                 if (e.isPresent()) {
 132                     throw new AssertionError();
 133                 }
 134                 count.compute(s, (k, c) -> 1 + (c == null ? 0 : c));
 135             }
 136             count.forEach((k, v) -> {
 137                 if (v != 1) {
 138                     throw new AssertionError("Expected one entry in the table, got: " + v + " for " + k);
 139                 }
 140             });
 141             inResources.entries().forEach(r -> {
 142                 outResources.add(r);
 143             });
 144 
 145             return outResources.build();
 146         }
 147 
 148         @Override
 149         public String getName() {
 150             return NAME;
 151         }
 152 
 153         @Override
 154         public void previsit(ResourcePool resources, StringTable strings) {
 155             isPrevisitCalled = true;
 156             resources.entries().forEach(r -> {
 157                 String s = r.path();
 158                 int lastIndexOf = s.lastIndexOf('/');
 159                 if (lastIndexOf >= 0) {
 160                     strings.addString(s.substring(0, lastIndexOf));
 161                 }
 162             });
 163         }
 164     }
 165 }