src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java
author jiangli
Sun, 08 Jul 2018 12:43:05 -0400
changeset 50951 b96466cdfc45
parent 49532 745ce8f5efc8
permissions -rw-r--r--
8202035: Archive the set of ModuleDescriptor and ModuleReference objects for observable system modules with unnamed initial module. Summary: Support system module archiving with unnamed initial module at dump time. Reviewed-by: erikj, coleenp, mchung, iklam, ccheung Contributed-by: alan.bateman@oracle.com, jiangli.zhou@oracle.com
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
     1
/*
49285
4d2e3f5abb48 8194746: (fs) Add equivalents of Paths.get to Path interface
bpb
parents: 47471
diff changeset
     2
 * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
     4
 *
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    10
 *
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    15
 * accompanied this code).
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    16
 *
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    20
 *
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    23
 * questions.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    24
 */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    25
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    26
package jdk.internal.module;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    27
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    28
import java.io.PrintStream;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    29
import java.lang.module.Configuration;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    30
import java.lang.module.ResolvedModule;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    31
import java.net.URI;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    32
import java.nio.file.Path;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    33
import java.util.ArrayDeque;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    34
import java.util.Collections;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    35
import java.util.Deque;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    36
import java.util.HashMap;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    37
import java.util.HashSet;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    38
import java.util.Map;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    39
import java.util.Set;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    40
import java.util.function.Consumer;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    41
import java.util.function.Function;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    42
import java.util.stream.Stream;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    43
import static java.util.stream.Collectors.*;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    44
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    45
/**
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    46
 * A Builder to compute ModuleHashes from a given configuration
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    47
 */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    48
public class ModuleHashesBuilder {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    49
    private final Configuration configuration;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    50
    private final Set<String> hashModuleCandidates;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    51
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    52
    /**
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    53
     * Constructs a ModuleHashesBuilder that finds the packaged modules
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    54
     * from the location of ModuleReference found from the given Configuration.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    55
     *
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    56
     * @param config Configuration for building module hashes
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    57
     * @param modules the candidate modules to be hashed
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    58
     */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    59
    public ModuleHashesBuilder(Configuration config, Set<String> modules) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    60
        this.configuration = config;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    61
        this.hashModuleCandidates = modules;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    62
    }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    63
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    64
    /**
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    65
     * Returns a map of a module M to ModuleHashes for the modules
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    66
     * that depend upon M directly or indirectly.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    67
     *
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    68
     * The key for each entry in the returned map is a module M that has
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    69
     * no outgoing edges to any of the candidate modules to be hashed
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    70
     * i.e. M is a leaf node in a connected subgraph containing M and
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    71
     * other candidate modules from the module graph filtering
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    72
     * the outgoing edges from M to non-candidate modules.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    73
     */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    74
    public Map<String, ModuleHashes> computeHashes(Set<String> roots) {
47471
304ef03403b1 8190323: "the the" typos
rriggs
parents: 47216
diff changeset
    75
        // build a graph containing the packaged modules and
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    76
        // its transitive dependences matching --hash-modules
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    77
        Graph.Builder<String> builder = new Graph.Builder<>();
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
    78
        Deque<ResolvedModule> todo = new ArrayDeque<>(configuration.modules());
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    79
        Set<ResolvedModule> visited = new HashSet<>();
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
    80
        ResolvedModule rm;
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
    81
        while ((rm = todo.poll()) != null) {
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
    82
            if (visited.add(rm)) {
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    83
                builder.addNode(rm.name());
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    84
                for (ResolvedModule dm : rm.reads()) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    85
                    if (!visited.contains(dm)) {
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
    86
                        todo.push(dm);
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    87
                    }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    88
                    builder.addEdge(rm.name(), dm.name());
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    89
                }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    90
            }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    91
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    92
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    93
        // each node in a transposed graph is a matching packaged module
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    94
        // in which the hash of the modules that depend upon it is recorded
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    95
        Graph<String> transposedGraph = builder.build().transpose();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    96
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    97
        // traverse the modules in topological order that will identify
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    98
        // the modules to record the hashes - it is the first matching
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
    99
        // module and has not been hashed during the traversal.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   100
        Set<String> mods = new HashSet<>();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   101
        Map<String, ModuleHashes> hashes = new HashMap<>();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   102
        builder.build()
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   103
               .orderedNodes()
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   104
               .filter(mn -> roots.contains(mn) && !mods.contains(mn))
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   105
               .forEach(mn -> {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   106
                   // Compute hashes of the modules that depend on mn directly and
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   107
                   // indirectly excluding itself.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   108
                   Set<String> ns = transposedGraph.dfs(mn)
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   109
                       .stream()
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   110
                       .filter(n -> !n.equals(mn) && hashModuleCandidates.contains(n))
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   111
                       .collect(toSet());
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   112
                   mods.add(mn);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   113
                   mods.addAll(ns);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   114
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   115
                   if (!ns.isEmpty()) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   116
                       Map<String, Path> moduleToPath = ns.stream()
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   117
                           .collect(toMap(Function.identity(), this::moduleToPath));
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   118
                       hashes.put(mn, ModuleHashes.generate(moduleToPath, "SHA-256"));
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   119
                   }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   120
               });
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   121
        return hashes;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   122
    }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   123
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   124
    private Path moduleToPath(String name) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   125
        ResolvedModule rm = configuration.findModule(name).orElseThrow(
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   126
            () -> new InternalError("Selected module " + name + " not on module path"));
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   127
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   128
        URI uri = rm.reference().location().get();
49285
4d2e3f5abb48 8194746: (fs) Add equivalents of Paths.get to Path interface
bpb
parents: 47471
diff changeset
   129
        Path path = Path.of(uri);
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   130
        String fn = path.getFileName().toString();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   131
        if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   132
            throw new UnsupportedOperationException(path + " is not a modular JAR or jmod file");
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   133
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   134
        return path;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   135
    }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   136
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   137
    /*
45004
ea3137042a61 8178380: Module system implementation refresh (5/2017)
alanb
parents: 43109
diff changeset
   138
     * Utility class
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   139
     */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   140
    static class Graph<T> {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   141
        private final Set<T> nodes;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   142
        private final Map<T, Set<T>> edges;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   143
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   144
        public Graph(Set<T> nodes, Map<T, Set<T>> edges) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   145
            this.nodes = Collections.unmodifiableSet(nodes);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   146
            this.edges = Collections.unmodifiableMap(edges);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   147
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   148
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   149
        public Set<T> nodes() {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   150
            return nodes;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   151
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   152
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   153
        public Map<T, Set<T>> edges() {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   154
            return edges;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   155
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   156
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   157
        public Set<T> adjacentNodes(T u) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   158
            return edges.get(u);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   159
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   160
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   161
        public boolean contains(T u) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   162
            return nodes.contains(u);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   163
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   164
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   165
        /**
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   166
         * Returns nodes sorted in topological order.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   167
         */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   168
        public Stream<T> orderedNodes() {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   169
            TopoSorter<T> sorter = new TopoSorter<>(this);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   170
            return sorter.result.stream();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   171
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   172
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   173
        /**
49528
c1eb35eb5f38 8200125: Fix some classloader/module typos
martin
parents: 49285
diff changeset
   174
         * Traverses this graph and performs the given action in topological order.
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   175
         */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   176
        public void ordered(Consumer<T> action) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   177
            TopoSorter<T> sorter = new TopoSorter<>(this);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   178
            sorter.ordered(action);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   179
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   180
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   181
        /**
49528
c1eb35eb5f38 8200125: Fix some classloader/module typos
martin
parents: 49285
diff changeset
   182
         * Traverses this graph and performs the given action in reverse topological order.
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   183
         */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   184
        public void reverse(Consumer<T> action) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   185
            TopoSorter<T> sorter = new TopoSorter<>(this);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   186
            sorter.reverse(action);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   187
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   188
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   189
        /**
49528
c1eb35eb5f38 8200125: Fix some classloader/module typos
martin
parents: 49285
diff changeset
   190
         * Returns a transposed graph from this graph.
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   191
         */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   192
        public Graph<T> transpose() {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   193
            Builder<T> builder = new Builder<>();
49529
c0bdb1b1ab4f 8200127: Replace collection.stream().forEach() with collection.forEach()
martin
parents: 49528
diff changeset
   194
            nodes.forEach(builder::addNode);
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   195
            // reverse edges
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   196
            edges.keySet().forEach(u -> {
49529
c0bdb1b1ab4f 8200127: Replace collection.stream().forEach() with collection.forEach()
martin
parents: 49528
diff changeset
   197
                edges.get(u).forEach(v -> builder.addEdge(v, u));
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   198
            });
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   199
            return builder.build();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   200
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   201
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   202
        /**
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   203
         * Returns all nodes reachable from the given root.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   204
         */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   205
        public Set<T> dfs(T root) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   206
            return dfs(Set.of(root));
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   207
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   208
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   209
        /**
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   210
         * Returns all nodes reachable from the given set of roots.
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   211
         */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   212
        public Set<T> dfs(Set<T> roots) {
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   213
            ArrayDeque<T> todo = new ArrayDeque<>(roots);
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   214
            Set<T> visited = new HashSet<>();
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   215
            T u;
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   216
            while ((u = todo.poll()) != null) {
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   217
                if (visited.add(u) && contains(u)) {
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   218
                    adjacentNodes(u).stream()
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   219
                        .filter(v -> !visited.contains(v))
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   220
                        .forEach(todo::push);
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   221
                }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   222
            }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   223
            return visited;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   224
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   225
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   226
        public void printGraph(PrintStream out) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   227
            out.println("graph for " + nodes);
49529
c0bdb1b1ab4f 8200127: Replace collection.stream().forEach() with collection.forEach()
martin
parents: 49528
diff changeset
   228
            nodes
c0bdb1b1ab4f 8200127: Replace collection.stream().forEach() with collection.forEach()
martin
parents: 49528
diff changeset
   229
                .forEach(u -> adjacentNodes(u)
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   230
                    .forEach(v -> out.format("  %s -> %s%n", u, v)));
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   231
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   232
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   233
        static class Builder<T> {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   234
            final Set<T> nodes = new HashSet<>();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   235
            final Map<T, Set<T>> edges = new HashMap<>();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   236
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   237
            public void addNode(T node) {
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   238
                if (nodes.add(node)) {
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   239
                    edges.computeIfAbsent(node, _e -> new HashSet<>());
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   240
                }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   241
            }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   242
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   243
            public void addEdge(T u, T v) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   244
                addNode(u);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   245
                addNode(v);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   246
                edges.get(u).add(v);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   247
            }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   248
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   249
            public Graph<T> build() {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   250
                return new Graph<T>(nodes, edges);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   251
            }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   252
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   253
    }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   254
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   255
    /**
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   256
     * Topological sort
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   257
     */
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   258
    private static class TopoSorter<T> {
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   259
        final Deque<T> result = new ArrayDeque<>();
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   260
        final Graph<T> graph;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   261
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   262
        TopoSorter(Graph<T> graph) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   263
            this.graph = graph;
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   264
            sort();
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   265
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   266
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   267
        public void ordered(Consumer<T> action) {
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   268
            result.forEach(action);
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   269
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   270
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   271
        public void reverse(Consumer<T> action) {
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   272
            result.descendingIterator().forEachRemaining(action);
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   273
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   274
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   275
        private void sort() {
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   276
            Set<T> visited = new HashSet<>();
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   277
            Deque<T> stack = new ArrayDeque<>();
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   278
            graph.nodes.forEach(node -> visit(node, visited, stack));
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   279
        }
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   280
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   281
        private Set<T> children(T node) {
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   282
            return graph.edges().get(node);
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   283
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   284
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   285
        private void visit(T node, Set<T> visited, Deque<T> stack) {
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   286
            if (visited.add(node)) {
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   287
                stack.push(node);
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   288
                children(node).forEach(child -> visit(child, visited, stack));
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   289
                stack.pop();
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   290
                result.addLast(node);
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   291
            }
49532
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   292
            else if (stack.contains(node)) {
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   293
                throw new IllegalArgumentException(
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   294
                    "Cycle detected: " + node + " -> " + children(node));
745ce8f5efc8 8200134: Improve ModuleHashesBuilder
martin
parents: 49529
diff changeset
   295
            }
43109
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   296
        }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   297
    }
fe275140c3f1 8160286: jmod hash is creating unlinkable modules
mchung
parents:
diff changeset
   298
}