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 */
33import java.nio.ByteOrder;
34import java.util.ArrayList;
35import java.util.Collection;
36import java.util.Collections;
37import java.util.HashMap;
38import java.util.List;
39import java.util.Map;
40import java.util.Optional;
41import java.util.stream.Collectors;
42
43import jdk.tools.jlink.internal.ImagePluginConfiguration;
44import jdk.tools.jlink.internal.Jlink;
45import jdk.tools.jlink.internal.PluginRepository;
46import jdk.tools.jlink.internal.ImagePluginStack;
47import jdk.tools.jlink.internal.ResourcePoolManager;
48import jdk.tools.jlink.internal.ResourcePoolManager.ResourcePoolImpl;
49import jdk.tools.jlink.internal.ResourcePrevisitor;
50import jdk.tools.jlink.internal.StringTable;
51import jdk.tools.jlink.plugin.Plugin;
52import jdk.tools.jlink.plugin.ResourcePool;
53import jdk.tools.jlink.plugin.ResourcePoolBuilder;
54import jdk.tools.jlink.plugin.ResourcePoolEntry;
55
56public 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}
166