1 /*
2  * Copyright (c) 2016, 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 
26 package jdk.internal.module;
27 
28 import java.io.IOException;
29 import java.io.UncheckedIOException;
30 import java.lang.module.ModuleDescriptor;
31 import java.lang.module.ModuleReader;
32 import java.lang.module.ModuleReference;
33 import java.net.URI;
34 import java.util.Objects;
35 import java.util.function.Supplier;
36 
37 /**
38  * A ModuleReference implementation that supports referencing a module that
39  * is patched and/or can be tied to other modules by means of hashes.
40  */
41 
42 public class ModuleReferenceImpl extends ModuleReference {
43 
44     // location of module
45     private final URI location;
46 
47     // the module reader
48     private final Supplier<ModuleReader> readerSupplier;
49 
50     // non-null if the module is patched
51     private final ModulePatcher patcher;
52 
53     // ModuleTarget if the module is OS/architecture specific
54     private final ModuleTarget target;
55 
56     // the hashes of other modules recorded in this module
57     private final ModuleHashes recordedHashes;
58 
59     // the function that computes the hash of this module
60     private final ModuleHashes.HashSupplier hasher;
61 
62     // ModuleResolution flags
63     private final ModuleResolution moduleResolution;
64 
65     // cached hash of this module to avoid needing to compute it many times
66     private byte[] cachedHash;
67 
68     /**
69      * Constructs a new instance of this class.
70      */
ModuleReferenceImpl(ModuleDescriptor descriptor, URI location, Supplier<ModuleReader> readerSupplier, ModulePatcher patcher, ModuleTarget target, ModuleHashes recordedHashes, ModuleHashes.HashSupplier hasher, ModuleResolution moduleResolution)71     public ModuleReferenceImpl(ModuleDescriptor descriptor,
72                                URI location,
73                                Supplier<ModuleReader> readerSupplier,
74                                ModulePatcher patcher,
75                                ModuleTarget target,
76                                ModuleHashes recordedHashes,
77                                ModuleHashes.HashSupplier hasher,
78                                ModuleResolution moduleResolution)
79     {
80         super(descriptor, Objects.requireNonNull(location));
81         this.location = location;
82         this.readerSupplier = readerSupplier;
83         this.patcher = patcher;
84         this.target = target;
85         this.recordedHashes = recordedHashes;
86         this.hasher = hasher;
87         this.moduleResolution = moduleResolution;
88     }
89 
90     @Override
open()91     public ModuleReader open() throws IOException {
92         try {
93             return readerSupplier.get();
94         } catch (UncheckedIOException e) {
95             throw e.getCause();
96         }
97     }
98 
99     /**
100      * Returns {@code true} if this module has been patched via --patch-module.
101      */
isPatched()102     public boolean isPatched() {
103         return (patcher != null);
104     }
105 
106     /**
107      * Returns the ModuleTarget or {@code null} if the no target platform.
108      */
moduleTarget()109     public ModuleTarget moduleTarget() {
110         return target;
111     }
112 
113     /**
114      * Returns the hashes recorded in this module or {@code null} if there
115      * are no hashes recorded.
116      */
recordedHashes()117     public ModuleHashes recordedHashes() {
118         return recordedHashes;
119     }
120 
121     /**
122      * Returns the supplier that computes the hash of this module.
123      */
hasher()124     ModuleHashes.HashSupplier hasher() {
125         return hasher;
126     }
127 
128     /**
129      * Returns the ModuleResolution flags.
130      */
moduleResolution()131     public ModuleResolution moduleResolution() {
132         return moduleResolution;
133     }
134 
135     /**
136      * Computes the hash of this module. Returns {@code null} if the hash
137      * cannot be computed.
138      *
139      * @throws java.io.UncheckedIOException if an I/O error occurs
140      */
computeHash(String algorithm)141     public byte[] computeHash(String algorithm) {
142         byte[] result = cachedHash;
143         if (result != null)
144             return result;
145         if (hasher == null)
146             return null;
147         cachedHash = result = hasher.generate(algorithm);
148         return result;
149     }
150 
151     @Override
hashCode()152     public int hashCode() {
153         int hc = hash;
154         if (hc == 0) {
155             hc = descriptor().hashCode();
156             hc = 43 * hc + Objects.hashCode(location);
157             hc = 43 * hc + Objects.hashCode(patcher);
158             if (hc == 0)
159                 hc = -1;
160             hash = hc;
161         }
162         return hc;
163     }
164 
165     private int hash;
166 
167     @Override
equals(Object ob)168     public boolean equals(Object ob) {
169         if (!(ob instanceof ModuleReferenceImpl))
170             return false;
171         ModuleReferenceImpl that = (ModuleReferenceImpl)ob;
172 
173         // assume module content, recorded hashes, etc. are the same
174         // when the modules have equal module descriptors, are at the
175         // same location, and are patched by the same patcher.
176         return Objects.equals(this.descriptor(), that.descriptor())
177                 && Objects.equals(this.location, that.location)
178                 && Objects.equals(this.patcher, that.patcher);
179     }
180 
181     @Override
toString()182     public String toString() {
183         StringBuilder sb = new StringBuilder();
184         sb.append("[module ");
185         sb.append(descriptor().name());
186         sb.append(", location=");
187         sb.append(location);
188         if (isPatched()) sb.append(" (patched)");
189         sb.append("]");
190         return sb.toString();
191     }
192 
193 }
194