|
1 /* |
|
2 * Copyright (c) 2014, 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. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 package com.sun.tools.jdeps; |
|
26 |
|
27 import java.util.Collections; |
|
28 import java.util.HashMap; |
|
29 import java.util.HashSet; |
|
30 import java.util.Map; |
|
31 import java.util.Objects; |
|
32 import java.util.Set; |
|
33 |
|
34 /** |
|
35 * JDeps internal representation of module for dependency analysis. |
|
36 */ |
|
37 final class Module extends Archive { |
|
38 private final String moduleName; |
|
39 private final Map<String, Boolean> requires; |
|
40 private final Map<String, Set<String>> exports; |
|
41 private final Set<String> packages; |
|
42 |
|
43 private Module(ClassFileReader reader, String name, |
|
44 Map<String, Boolean> requires, |
|
45 Map<String, Set<String>> exports, |
|
46 Set<String> packages) { |
|
47 super(name, reader); |
|
48 this.moduleName = name; |
|
49 this.requires = Collections.unmodifiableMap(requires); |
|
50 this.exports = Collections.unmodifiableMap(exports); |
|
51 this.packages = Collections.unmodifiableSet(packages); |
|
52 } |
|
53 |
|
54 public String name() { |
|
55 return moduleName; |
|
56 } |
|
57 |
|
58 public Map<String, Boolean> requires() { |
|
59 return requires; |
|
60 } |
|
61 |
|
62 public Map<String, Set<String>> exports() { |
|
63 return exports; |
|
64 } |
|
65 |
|
66 public Set<String> packages() { |
|
67 return packages; |
|
68 } |
|
69 |
|
70 /** |
|
71 * Tests if this module can read m |
|
72 */ |
|
73 public boolean canRead(Module m) { |
|
74 // ## TODO: handle "re-exported=true" |
|
75 // all JDK modules require all modules containing its direct dependences |
|
76 // should not be an issue |
|
77 return requires.containsKey(m.name()); |
|
78 } |
|
79 |
|
80 /** |
|
81 * Tests if a given fully-qualified name is an exported type. |
|
82 */ |
|
83 public boolean isExported(String cn) { |
|
84 int i = cn.lastIndexOf('.'); |
|
85 String pn = i > 0 ? cn.substring(0, i) : ""; |
|
86 |
|
87 return isExportedPackage(pn); |
|
88 } |
|
89 |
|
90 /** |
|
91 * Tests if a given package name is exported. |
|
92 */ |
|
93 public boolean isExportedPackage(String pn) { |
|
94 return exports.containsKey(pn) ? exports.get(pn).isEmpty() : false; |
|
95 } |
|
96 |
|
97 /** |
|
98 * Tests if the given classname is accessible to module m |
|
99 */ |
|
100 public boolean isAccessibleTo(String classname, Module m) { |
|
101 int i = classname.lastIndexOf('.'); |
|
102 String pn = i > 0 ? classname.substring(0, i) : ""; |
|
103 if (!packages.contains(pn)) { |
|
104 throw new IllegalArgumentException(classname + " is not a member of module " + name()); |
|
105 } |
|
106 |
|
107 if (m != null && !m.canRead(this)) { |
|
108 trace("%s not readable by %s%n", this.name(), m.name()); |
|
109 return false; |
|
110 } |
|
111 |
|
112 // exported API |
|
113 Set<String> ms = exports().get(pn); |
|
114 String mname = m != null ? m.name() : "unnamed"; |
|
115 if (ms == null) { |
|
116 trace("%s not exported in %s%n", classname, this.name()); |
|
117 } else if (!(ms.isEmpty() || ms.contains(mname))) { |
|
118 trace("%s not permit to %s %s%n", classname, mname, ms); |
|
119 } |
|
120 return ms != null && (ms.isEmpty() || ms.contains(mname)); |
|
121 } |
|
122 |
|
123 private static final boolean traceOn = Boolean.getBoolean("jdeps.debug"); |
|
124 private void trace(String fmt, Object... args) { |
|
125 if (traceOn) { |
|
126 System.err.format(fmt, args); |
|
127 } |
|
128 } |
|
129 |
|
130 @Override |
|
131 public boolean equals(Object ob) { |
|
132 if (!(ob instanceof Module)) |
|
133 return false; |
|
134 Module that = (Module)ob; |
|
135 return (moduleName.equals(that.moduleName) |
|
136 && requires.equals(that.requires) |
|
137 && exports.equals(that.exports) |
|
138 && packages.equals(that.packages)); |
|
139 } |
|
140 |
|
141 @Override |
|
142 public int hashCode() { |
|
143 int hc = moduleName.hashCode(); |
|
144 hc = hc * 43 + requires.hashCode(); |
|
145 hc = hc * 43 + exports.hashCode(); |
|
146 hc = hc * 43 + packages.hashCode(); |
|
147 return hc; |
|
148 } |
|
149 |
|
150 @Override |
|
151 public String toString() { |
|
152 return name(); |
|
153 } |
|
154 |
|
155 public final static class Builder { |
|
156 String name; |
|
157 ClassFileReader reader; |
|
158 final Map<String, Boolean> requires = new HashMap<>(); |
|
159 final Map<String, Set<String>> exports = new HashMap<>(); |
|
160 final Set<String> packages = new HashSet<>(); |
|
161 |
|
162 public Builder() { |
|
163 } |
|
164 |
|
165 public Builder name(String n) { |
|
166 name = n; |
|
167 return this; |
|
168 } |
|
169 |
|
170 public Builder require(String d, boolean reexport) { |
|
171 // System.err.format("%s depend %s reexports %s%n", name, d, reexport); |
|
172 requires.put(d, reexport); |
|
173 return this; |
|
174 } |
|
175 |
|
176 public Builder packages(Set<String> pkgs) { |
|
177 packages.addAll(pkgs); |
|
178 return this; |
|
179 } |
|
180 |
|
181 public Builder export(String p, Set<String> ms) { |
|
182 Objects.requireNonNull(p); |
|
183 Objects.requireNonNull(ms); |
|
184 exports.put(p, new HashSet<>(ms)); |
|
185 return this; |
|
186 } |
|
187 public Builder classes(ClassFileReader.ModuleClassReader reader) { |
|
188 this.reader = reader; |
|
189 return this; |
|
190 } |
|
191 |
|
192 public Module build() { |
|
193 Module m = new Module(reader, name, requires, exports, packages); |
|
194 return m; |
|
195 } |
|
196 } |
|
197 } |