Module.java revision 3792:d516975e8110
137985Sphk/*
237985Sphk * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
337985Sphk * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
437985Sphk *
537985Sphk * This code is free software; you can redistribute it and/or modify it
637985Sphk * under the terms of the GNU General Public License version 2 only, as
737985Sphk * published by the Free Software Foundation.  Oracle designates this
837985Sphk * particular file as subject to the "Classpath" exception as provided
937985Sphk * by Oracle in the LICENSE file that accompanied this code.
1037985Sphk *
1137985Sphk * This code is distributed in the hope that it will be useful, but WITHOUT
1237985Sphk * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1337985Sphk * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1437985Sphk * version 2 for more details (a copy is included in the LICENSE file that
1537985Sphk * accompanied this code).
1637985Sphk *
1737985Sphk * You should have received a copy of the GNU General Public License version
1837985Sphk * 2 along with this work; if not, write to the Free Software Foundation,
1937985Sphk * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2037985Sphk *
2137985Sphk * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2237985Sphk * or visit www.oracle.com if you need additional information or have any
2337985Sphk * questions.
2437985Sphk */
2537985Sphk
2637985Sphkpackage com.sun.tools.jdeps;
2737985Sphk
2850476Speterimport java.lang.module.ModuleDescriptor;
2948794Snikimport java.lang.module.ModuleDescriptor.Exports;
3037985Sphkimport java.lang.module.ModuleDescriptor.Opens;
3137985Sphkimport java.net.URI;
3279531Sruimport java.util.Collections;
3337985Sphkimport java.util.HashMap;
3437985Sphkimport java.util.HashSet;
3537985Sphkimport java.util.Map;
3659501Sphantomimport java.util.Set;
37124535Sru
3837985Sphk/**
3984306Sru * Jdeps internal representation of module for dependency analysis.
4037985Sphk */
4137985Sphkclass Module extends Archive {
4237985Sphk    static final Module UNNAMED_MODULE = new UnnamedModule();
4337985Sphk    static final String JDK_UNSUPPORTED = "jdk.unsupported";
4437985Sphk
4537985Sphk    static final boolean DEBUG = Boolean.getBoolean("jdeps.debug");
4637985Sphk    static void trace(String fmt, Object... args) {
4737985Sphk        trace(DEBUG, fmt, args);
4837985Sphk    }
4937985Sphk
5037985Sphk    static void trace(boolean traceOn, String fmt, Object... args) {
5137985Sphk        if (traceOn) {
5237985Sphk            System.err.format(fmt, args);
53110442Scharnier        }
5437985Sphk    }
55110442Scharnier
5637985Sphk    private final ModuleDescriptor descriptor;
5737985Sphk    private final Map<String, Set<String>> exports;
5837985Sphk    private final boolean isSystem;
5937985Sphk    private final URI location;
6037985Sphk
6137985Sphk    protected Module(String name) {
6237985Sphk        super(name);
6338702Swosch        this.descriptor = null;
6437985Sphk        this.location = null;
6538702Swosch        this.exports = Collections.emptyMap();
6637985Sphk        this.isSystem = true;
6738702Swosch    }
6837985Sphk
69110442Scharnier    private Module(String name,
7037985Sphk                   URI location,
71110442Scharnier                   ModuleDescriptor descriptor,
7273093Sru                   Map<String, Set<String>> exports,
73                   boolean isSystem,
74                   ClassFileReader reader) {
75        super(name, location, reader);
76        this.descriptor = descriptor;
77        this.location = location;
78        this.exports = Collections.unmodifiableMap(exports);
79        this.isSystem = isSystem;
80    }
81
82    /**
83     * Returns module name
84     */
85    public String name() {
86        return descriptor != null ? descriptor.name() : getName();
87    }
88
89    public boolean isNamed() {
90        return true;
91    }
92
93    public boolean isAutomatic() {
94        return descriptor.isAutomatic();
95    }
96
97    public Module getModule() {
98        return this;
99    }
100
101    public ModuleDescriptor descriptor() {
102        return descriptor;
103    }
104
105    public URI location() {
106        return location;
107    }
108
109    public boolean isJDK() {
110        String mn = name();
111        return isSystem &&
112            (mn.startsWith("java.") || mn.startsWith("jdk.") || mn.startsWith("javafx."));
113    }
114
115    public boolean isSystem() {
116        return isSystem;
117    }
118
119    public Map<String, Set<String>> exports() {
120        return exports;
121    }
122
123    public Set<String> packages() {
124        return descriptor.packages();
125    }
126
127    /**
128     * Tests if the package of the given name is exported.
129     */
130    public boolean isExported(String pn) {
131        return exports.containsKey(pn) ? exports.get(pn).isEmpty() : false;
132    }
133
134    public boolean isJDKUnsupported() {
135        return JDK_UNSUPPORTED.equals(this.name());
136    }
137
138    /**
139     * Converts this module to a strict module with the given dependences
140     *
141     * @throws IllegalArgumentException if this module is not an automatic module
142     */
143    public Module toStrictModule(Map<String, Boolean> requires) {
144        if (!isAutomatic()) {
145            throw new IllegalArgumentException(name() + " already a strict module");
146        }
147        return new StrictModule(this, requires);
148    }
149
150    /**
151     * Tests if the package of the given name is qualifiedly exported
152     * to the target.
153     */
154    public boolean isExported(String pn, String target) {
155        return isExported(pn) || exports.containsKey(pn) && exports.get(pn).contains(target);
156    }
157
158    @Override
159    public String toString() {
160        return name();
161    }
162
163    public final static class Builder {
164        final String name;
165        final ModuleDescriptor descriptor;
166        final boolean isSystem;
167        ClassFileReader reader;
168        URI location;
169
170        public Builder(ModuleDescriptor md) {
171            this(md, false);
172        }
173
174        public Builder(ModuleDescriptor md, boolean isSystem) {
175            this.name = md.name();
176            this.descriptor = md;
177            this.isSystem = isSystem;
178        }
179
180        public Builder location(URI location) {
181            this.location = location;
182            return this;
183        }
184
185        public Builder classes(ClassFileReader reader) {
186            this.reader = reader;
187            return this;
188        }
189
190        public Module build() {
191            if (descriptor.isAutomatic() && isSystem) {
192                throw new InternalError("JDK module: " + name + " can't be automatic module");
193            }
194
195            Map<String, Set<String>> exports = new HashMap<>();
196
197            descriptor.exports().stream()
198                .forEach(exp -> exports.computeIfAbsent(exp.source(), _k -> new HashSet<>())
199                                    .addAll(exp.targets()));
200
201            return new Module(name, location, descriptor, exports, isSystem, reader);
202        }
203    }
204
205    private static class UnnamedModule extends Module {
206        private UnnamedModule() {
207            super("unnamed", null, null,
208                  Collections.emptyMap(),
209                  false, null);
210        }
211
212        @Override
213        public String name() {
214            return "unnamed";
215        }
216
217        @Override
218        public boolean isNamed() {
219            return false;
220        }
221
222        @Override
223        public boolean isAutomatic() {
224            return false;
225        }
226
227        @Override
228        public boolean isExported(String pn) {
229            return true;
230        }
231    }
232
233    private static class StrictModule extends Module {
234        private final ModuleDescriptor md;
235
236        /**
237         * Converts the given automatic module to a strict module.
238         *
239         * Replace this module's dependences with the given requires and also
240         * declare service providers, if specified in META-INF/services configuration file
241         */
242        private StrictModule(Module m, Map<String, Boolean> requires) {
243            super(m.name(), m.location, m.descriptor, m.exports, m.isSystem, m.reader());
244
245            ModuleDescriptor.Builder builder = ModuleDescriptor.module(m.name());
246            requires.keySet().forEach(mn -> {
247                if (requires.get(mn).equals(Boolean.TRUE)) {
248                    builder.requires(Set.of(ModuleDescriptor.Requires.Modifier.TRANSITIVE), mn);
249                } else {
250                    builder.requires(mn);
251                }
252            });
253            m.descriptor.exports().forEach(e -> builder.exports(e));
254            m.descriptor.opens().forEach(o -> builder.opens(o));
255            m.descriptor.uses().forEach(s -> builder.uses(s));
256            m.descriptor.provides().forEach(p -> builder.provides(p));
257
258            Set<String> concealed = new HashSet<>(m.descriptor.packages());
259            m.descriptor.exports().stream().map(Exports::source).forEach(concealed::remove);
260            m.descriptor.opens().stream().map(Opens::source).forEach(concealed::remove);
261            concealed.forEach(builder::contains);
262
263            this.md = builder.build();
264        }
265
266        @Override
267        public ModuleDescriptor descriptor() {
268            return md;
269        }
270    }
271}
272