/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.tools.jlink.internal.plugins;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.ToIntFunction;
import jdk.tools.jlink.internal.Utils;
import jdk.tools.jlink.plugin.Plugin;
import jdk.tools.jlink.plugin.ResourcePool;
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
import jdk.tools.jlink.plugin.ResourcePoolEntry;
Order Resources plugin
/**
*
* Order Resources plugin
*/
public final class OrderResourcesPlugin implements Plugin {
public static final String NAME = "order-resources";
private static final FileSystem JRT_FILE_SYSTEM = Utils.jrtFileSystem();
private final List<ToIntFunction<String>> filters;
private final Map<String, Integer> orderedPaths;
public OrderResourcesPlugin() {
this.filters = new ArrayList<>();
this.orderedPaths = new HashMap<>();
}
@Override
public String getName() {
return NAME;
}
static class SortWrapper {
private final ResourcePoolEntry resource;
private final int ordinal;
SortWrapper(ResourcePoolEntry resource, int ordinal) {
this.resource = resource;
this.ordinal = ordinal;
}
ResourcePoolEntry getResource() {
return resource;
}
String getPath() {
return resource.path();
}
int getOrdinal() {
return ordinal;
}
}
private String stripModule(String path) {
if (path.startsWith("/")) {
int index = path.indexOf('/', 1);
if (index != -1) {
return path.substring(index + 1);
}
}
return path;
}
private int getOrdinal(ResourcePoolEntry resource) {
String path = resource.path();
Integer value = orderedPaths.get(stripModule(path));
if (value != null) {
return value;
}
for (ToIntFunction<String> function : filters) {
int ordinal = function.applyAsInt(path);
if (ordinal != Integer.MAX_VALUE) {
return ordinal;
}
}
return Integer.MAX_VALUE;
}
private static int compare(SortWrapper wrapper1, SortWrapper wrapper2) {
int compare = wrapper1.getOrdinal() - wrapper2.getOrdinal();
if (compare != 0) {
return compare;
}
return wrapper1.getPath().compareTo(wrapper2.getPath());
}
@Override
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
in.entries()
.filter(resource -> resource.type()
.equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE))
.map((resource) -> new SortWrapper(resource, getOrdinal(resource)))
.sorted(OrderResourcesPlugin::compare)
.forEach((wrapper) -> out.add(wrapper.getResource()));
in.entries()
.filter(other -> !other.type()
.equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE))
.forEach((other) -> out.add(other));
return out.build();
}
@Override
public Category getType() {
return Category.SORTER;
}
@Override
public String getDescription() {
return PluginsResourceBundle.getDescription(NAME);
}
@Override
public boolean hasArguments() {
return true;
}
@Override
public String getArgumentsDescription() {
return PluginsResourceBundle.getArgument(NAME);
}
@Override
public void configure(Map<String, String> config) {
List<String> patterns = Utils.parseList(config.get(NAME));
int ordinal = 0;
for (String pattern : patterns) {
if (pattern.startsWith("@")) {
File file = new File(pattern.substring(1));
if (file.exists()) {
List<String> lines;
try {
lines = Files.readAllLines(file.toPath());
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
for (String line : lines) {
if (!line.startsWith("#")) {
orderedPaths.put(line + ".class", ordinal++);
}
}
}
} else {
final int result = ordinal++;
final PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, pattern);
ToIntFunction<String> function = (path)-> matcher.matches(JRT_FILE_SYSTEM.getPath(path)) ? result : Integer.MAX_VALUE;
filters.add(function);
}
}
}
}