23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package java.lang; |
26 package java.lang; |
27 |
27 |
|
28 import java.lang.annotation.Annotation; |
28 import java.lang.reflect.AnnotatedElement; |
29 import java.lang.reflect.AnnotatedElement; |
29 |
30 import java.lang.reflect.Module; |
30 import java.io.File; |
31 import java.net.MalformedURLException; |
31 import java.io.FileInputStream; |
32 import java.net.URI; |
32 import java.io.IOException; |
|
33 import java.net.URL; |
33 import java.net.URL; |
34 import java.net.MalformedURLException; |
|
35 import java.security.AccessController; |
34 import java.security.AccessController; |
36 import java.security.PrivilegedAction; |
35 import java.security.PrivilegedAction; |
37 |
36 import java.util.Objects; |
38 import java.util.concurrent.ConcurrentHashMap; |
37 |
39 import java.util.jar.JarInputStream; |
38 import jdk.internal.loader.BootLoader; |
40 import java.util.jar.Manifest; |
|
41 import java.util.jar.Attributes; |
|
42 import java.util.jar.Attributes.Name; |
|
43 import java.util.Map; |
|
44 |
|
45 import sun.net.www.ParseUtil; |
|
46 import sun.reflect.CallerSensitive; |
39 import sun.reflect.CallerSensitive; |
47 import sun.reflect.Reflection; |
40 import sun.reflect.Reflection; |
48 |
41 |
49 import java.lang.annotation.Annotation; |
|
50 |
42 |
51 /** |
43 /** |
52 * {@code Package} objects contain version information |
44 * Represents metadata about a run-time package associated with a class loader. |
53 * about the implementation and specification of a Java package. |
45 * Metadata includes annotations, versioning, and sealing. |
54 * This versioning information is retrieved and made available |
46 * <p> |
55 * by the {@link ClassLoader} instance that |
47 * Annotations for the run-time package are read from {@code package-info.class} |
56 * loaded the class(es). Typically, it is stored in the manifest that is |
48 * at the same code source as classes in the run-time package. |
57 * distributed with the classes. |
49 * <p> |
58 * |
50 * The set of classes that make up the run-time package may implement a |
59 * <p>The set of classes that make up the package may implement a |
51 * particular specification. The specification title, version, and vendor |
60 * particular specification and if so the specification title, version number, |
52 * (indicating the owner/maintainer of the specification) can be provided |
61 * and vendor strings identify that specification. |
53 * when the {@code Package} is defined. An application can ask if the |
62 * An application can ask if the package is |
54 * {@code Package} is compatible with a particular specification version |
63 * compatible with a particular version, see the {@link |
55 * by using the {@link #isCompatibleWith Package.isCompatibleWith(String)} |
64 * #isCompatibleWith isCompatibleWith} |
56 * method. In addition, information about the actual classes that make up the |
65 * method for details. |
57 * run-time package can be provided when the Package is defined. |
66 * |
58 * This information consists of an implementation title, version, and vendor |
67 * <p>Specification version numbers use a syntax that consists of nonnegative |
59 * (indicating the supplier of the classes). |
68 * decimal integers separated by periods ".", for example "2.0" or |
60 * <p> |
69 * "1.2.3.4.5.6.7". This allows an extensible number to be used to represent |
61 * A {@code Package} may be explicitly defined with |
70 * major, minor, micro, etc. versions. The version specification is described |
62 * the {@link ClassLoader#definePackage(String, String, String, String, |
71 * by the following formal grammar: |
63 * String, String, String, URL)} method. |
72 * <blockquote> |
64 * The caller supplies the specification and implementation titles, versions, and |
73 * <dl> |
65 * vendors. The caller also indicates whether the package is |
74 * <dt><i>SpecificationVersion:</i> |
66 * {@linkplain java.util.jar.Attributes.Name#SEALED sealed}. |
75 * <dd><i>Digits RefinedVersion<sub>opt</sub></i> |
67 * If a {@code Package} is not explicitly defined for a run-time package when |
76 |
68 * a class in that run-time package is defined, then a {@code Package} is |
77 * <dt><i>RefinedVersion:</i> |
69 * automatically defined by the class's defining class loader, as follows. |
78 * <dd>{@code .} <i>Digits</i> |
70 * <p> |
79 * <dd>{@code .} <i>Digits RefinedVersion</i> |
71 * A {@code Package} automatically defined for classes in a named module has |
80 * |
72 * the following properties: |
81 * <dt><i>Digits:</i> |
73 * <ul> |
82 * <dd><i>Digit</i> |
74 * <li>The name of the package is derived from the {@linkplain Class#getName() binary names} |
83 * <dd><i>Digits</i> |
75 * of the classes. Since classes in a named module must be in a named package, |
84 * |
76 * the derived name is never empty.</li> |
85 * <dt><i>Digit:</i> |
77 * <li>The package is sealed with the {@linkplain java.lang.module.ModuleReference#location() |
86 * <dd>any character for which {@link Character#isDigit} returns {@code true}, |
78 * module location} as the code source, if known.</li> |
87 * e.g. 0, 1, 2, ... |
79 * <li>The specification and implementation titles, versions, and vendors |
88 * </dl> |
80 * are unspecified.</li> |
89 * </blockquote> |
81 * <li>Any annotations on the package are read from {@code package-info.class} |
90 * |
82 * as specified above.</li> |
91 * <p>The implementation title, version, and vendor strings identify an |
83 * </ul> |
92 * implementation and are made available conveniently to enable accurate |
84 * <p> |
93 * reporting of the packages involved when a problem occurs. The contents |
85 * A {@code Package} automatically defined for classes in an unnamed module |
94 * all three implementation strings are vendor specific. The |
86 * has the following properties: |
95 * implementation version strings have no specified syntax and should |
87 * <ul> |
96 * only be compared for equality with desired version identifiers. |
88 * <li>The name of the package is either {@code ""} (for classes in an unnamed package) |
97 * |
89 * or derived from the {@linkplain Class#getName() binary names} of the classes |
98 * <p>Within each {@code ClassLoader} instance all classes from the same |
90 * (for classes in a named package).</li> |
99 * java package have the same Package object. The static methods allow a package |
91 * <li>The package is not sealed.</li> |
100 * to be found by name or the set of all packages known to the current class |
92 * <li>The specification and implementation titles, versions, and vendors |
101 * loader to be found. |
93 * are unspecified.</li> |
102 * |
94 * <li>Any annotations on the package are read from {@code package-info.class} |
103 * @see ClassLoader#definePackage |
95 * as specified above.</li> |
|
96 * </ul> |
|
97 * |
|
98 * <p> |
|
99 * A {@code Package} can be obtained with the {@link Package#getPackage |
|
100 * Package.getPackage(String)} and {@link ClassLoader#getDefinedPackage |
|
101 * ClassLoader.getDefinedPackage(String)} methods. |
|
102 * Every {@code Package} defined by a class loader can be obtained |
|
103 * with the {@link Package#getPackages Package.getPackages()} and |
|
104 * {@link ClassLoader#getDefinedPackages} methods. |
|
105 * |
|
106 * @jvms 5.3 Run-time package |
|
107 * @see <a href="../../../technotes/guides/jar/jar.html#versioning"> |
|
108 * The JAR File Specification: Package Versioning</a> |
|
109 * @see <a href="../../../technotes/guides/jar/jar.html#sealing"> |
|
110 * The JAR File Specification: Package Sealing</a> |
|
111 * @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL) |
|
112 * |
104 * @since 1.2 |
113 * @since 1.2 |
105 */ |
114 */ |
106 public class Package implements java.lang.reflect.AnnotatedElement { |
115 public class Package extends NamedPackage implements java.lang.reflect.AnnotatedElement { |
107 /** |
116 /** |
108 * Return the name of this package. |
117 * Return the name of this package. |
109 * |
118 * |
110 * @return The fully-qualified name of this package as defined in section 6.5.3 of |
119 * @return The fully-qualified name of this package as defined in section 6.5.3 of |
111 * <cite>The Java™ Language Specification</cite>, |
120 * <cite>The Java™ Language Specification</cite>, |
112 * for example, {@code java.lang} |
121 * for example, {@code java.lang} |
113 */ |
122 */ |
114 public String getName() { |
123 public String getName() { |
115 return pkgName; |
124 return packageName(); |
116 } |
125 } |
117 |
|
118 |
126 |
119 /** |
127 /** |
120 * Return the title of the specification that this package implements. |
128 * Return the title of the specification that this package implements. |
121 * @return the specification title, null is returned if it is not known. |
129 * @return the specification title, {@code null} is returned if it is not known. |
122 */ |
130 */ |
123 public String getSpecificationTitle() { |
131 public String getSpecificationTitle() { |
124 return specTitle; |
132 return versionInfo.specTitle; |
125 } |
133 } |
126 |
134 |
127 /** |
135 /** |
128 * Returns the version number of the specification |
136 * Returns the version number of the specification |
129 * that this package implements. |
137 * that this package implements. |
130 * This version string must be a sequence of nonnegative decimal |
138 * This version string must be a sequence of non-negative decimal |
131 * integers separated by "."'s and may have leading zeros. |
139 * integers separated by "."'s and may have leading zeros. |
132 * When version strings are compared the most significant |
140 * When version strings are compared the most significant |
133 * numbers are compared. |
141 * numbers are compared. |
134 * @return the specification version, null is returned if it is not known. |
142 * |
|
143 * |
|
144 * <p>Specification version numbers use a syntax that consists of non-negative |
|
145 * decimal integers separated by periods ".", for example "2.0" or |
|
146 * "1.2.3.4.5.6.7". This allows an extensible number to be used to represent |
|
147 * major, minor, micro, etc. versions. The version specification is described |
|
148 * by the following formal grammar: |
|
149 * <blockquote> |
|
150 * <dl> |
|
151 * <dt><i>SpecificationVersion:</i> |
|
152 * <dd><i>Digits RefinedVersion<sub>opt</sub></i> |
|
153 |
|
154 * <dt><i>RefinedVersion:</i> |
|
155 * <dd>{@code .} <i>Digits</i> |
|
156 * <dd>{@code .} <i>Digits RefinedVersion</i> |
|
157 * |
|
158 * <dt><i>Digits:</i> |
|
159 * <dd><i>Digit</i> |
|
160 * <dd><i>Digits</i> |
|
161 * |
|
162 * <dt><i>Digit:</i> |
|
163 * <dd>any character for which {@link Character#isDigit} returns {@code true}, |
|
164 * e.g. 0, 1, 2, ... |
|
165 * </dl> |
|
166 * </blockquote> |
|
167 * |
|
168 * @return the specification version, {@code null} is returned if it is not known. |
135 */ |
169 */ |
136 public String getSpecificationVersion() { |
170 public String getSpecificationVersion() { |
137 return specVersion; |
171 return versionInfo.specVersion; |
138 } |
172 } |
139 |
173 |
140 /** |
174 /** |
141 * Return the name of the organization, vendor, |
175 * Return the name of the organization, vendor, |
142 * or company that owns and maintains the specification |
176 * or company that owns and maintains the specification |
143 * of the classes that implement this package. |
177 * of the classes that implement this package. |
144 * @return the specification vendor, null is returned if it is not known. |
178 * @return the specification vendor, {@code null} is returned if it is not known. |
145 */ |
179 */ |
146 public String getSpecificationVendor() { |
180 public String getSpecificationVendor() { |
147 return specVendor; |
181 return versionInfo.specVendor; |
148 } |
182 } |
149 |
183 |
150 /** |
184 /** |
151 * Return the title of this package. |
185 * Return the title of this package. |
152 * @return the title of the implementation, null is returned if it is not known. |
186 * @return the title of the implementation, {@code null} is returned if it is not known. |
153 */ |
187 */ |
154 public String getImplementationTitle() { |
188 public String getImplementationTitle() { |
155 return implTitle; |
189 return versionInfo.implTitle; |
156 } |
190 } |
157 |
191 |
158 /** |
192 /** |
159 * Return the version of this implementation. It consists of any string |
193 * Return the version of this implementation. It consists of any string |
160 * assigned by the vendor of this implementation and does |
194 * assigned by the vendor of this implementation and does |
161 * not have any particular syntax specified or expected by the Java |
195 * not have any particular syntax specified or expected by the Java |
162 * runtime. It may be compared for equality with other |
196 * runtime. It may be compared for equality with other |
163 * package version strings used for this implementation |
197 * package version strings used for this implementation |
164 * by this vendor for this package. |
198 * by this vendor for this package. |
165 * @return the version of the implementation, null is returned if it is not known. |
199 * @return the version of the implementation, {@code null} is returned if it is not known. |
166 */ |
200 */ |
167 public String getImplementationVersion() { |
201 public String getImplementationVersion() { |
168 return implVersion; |
202 return versionInfo.implVersion; |
169 } |
203 } |
170 |
204 |
171 /** |
205 /** |
172 * Returns the name of the organization, |
206 * Returns the vendor that implemented this package, {@code null} |
173 * vendor or company that provided this implementation. |
207 * is returned if it is not known. |
174 * @return the vendor that implemented this package.. |
208 * @return the vendor that implemented this package, {@code null} |
|
209 * is returned if it is not known. |
175 */ |
210 */ |
176 public String getImplementationVendor() { |
211 public String getImplementationVendor() { |
177 return implVendor; |
212 return versionInfo.implVendor; |
178 } |
213 } |
179 |
214 |
180 /** |
215 /** |
181 * Returns true if this package is sealed. |
216 * Returns true if this package is sealed. |
182 * |
217 * |
183 * @return true if the package is sealed, false otherwise |
218 * @return true if the package is sealed, false otherwise |
184 */ |
219 */ |
185 public boolean isSealed() { |
220 public boolean isSealed() { |
186 return sealBase != null; |
221 return module().isNamed() || versionInfo.sealBase != null; |
187 } |
222 } |
188 |
223 |
189 /** |
224 /** |
190 * Returns true if this package is sealed with respect to the specified |
225 * Returns true if this package is sealed with respect to the specified |
191 * code source url. |
226 * code source {@code url}. |
192 * |
227 * |
193 * @param url the code source url |
228 * @param url the code source URL |
194 * @return true if this package is sealed with respect to url |
229 * @return true if this package is sealed with respect to the given {@code url} |
195 */ |
230 */ |
196 public boolean isSealed(URL url) { |
231 public boolean isSealed(URL url) { |
|
232 Objects.requireNonNull(url); |
|
233 |
|
234 URL sealBase = null; |
|
235 if (versionInfo != VersionInfo.NULL_VERSION_INFO) { |
|
236 sealBase = versionInfo.sealBase; |
|
237 } else { |
|
238 try { |
|
239 URI uri = location(); |
|
240 sealBase = uri != null ? uri.toURL() : null; |
|
241 } catch (MalformedURLException e) { |
|
242 } |
|
243 } |
197 return url.equals(sealBase); |
244 return url.equals(sealBase); |
198 } |
245 } |
199 |
246 |
200 /** |
247 /** |
201 * Compare this package's specification version with a |
248 * Compare this package's specification version with a |
253 } |
300 } |
254 return true; |
301 return true; |
255 } |
302 } |
256 |
303 |
257 /** |
304 /** |
258 * Find a package by name in the callers {@code ClassLoader} instance. |
305 * Finds a package by name in the caller's class loader and its |
259 * The callers {@code ClassLoader} instance is used to find the package |
306 * ancestors. |
260 * instance corresponding to the named class. If the callers |
307 * <p> |
261 * {@code ClassLoader} instance is null then the set of packages loaded |
308 * If the caller's class loader defines a {@code Package} of the given name, |
262 * by the system {@code ClassLoader} instance is searched to find the |
309 * the {@code Package} is returned. Otherwise, the ancestors of the |
263 * named package. <p> |
310 * caller's class loader are searched recursively (parent by parent) |
264 * |
311 * for a {@code Package} of the given name. |
265 * Packages have attributes for versions and specifications only if the class |
312 * <p> |
266 * loader created the package instance with the appropriate attributes. Typically, |
313 * Calling this method is equivalent to calling {@link ClassLoader#getPackage} |
267 * those attributes are defined in the manifests that accompany the classes. |
314 * on a {@code ClassLoader} instance which is the caller's class loader. |
268 * |
315 * |
269 * @param name a package name, for example, java.lang. |
316 * @param name A package name, such as "{@code java.lang}". |
270 * @return the package of the requested name. It may be null if no package |
317 * @return The {@code Package} of the given name defined by the caller's |
271 * information is available from the archive or codebase. |
318 * class loader or its ancestors, or {@code null} if not found. |
|
319 * |
|
320 * @deprecated |
|
321 * If multiple class loaders delegate to each other and define classes |
|
322 * with the same package name, and one such loader relies on the lookup |
|
323 * behavior of {@code getPackage} to return a {@code Package} from |
|
324 * a parent loader, then the properties exposed by the {@code Package} |
|
325 * may not be as expected in the rest of the program. |
|
326 * For example, the {@code Package} will only expose annotations from the |
|
327 * {@code package-info.class} file defined by the parent loader, even if |
|
328 * annotations exist in a {@code package-info.class} file defined by |
|
329 * a child loader. A more robust approach is to use the |
|
330 * {@link ClassLoader#getDefinedPackage} method which returns |
|
331 * a {@code Package} for the specified class loader. |
|
332 * |
|
333 * @see ClassLoader#getDefinedPackage |
272 */ |
334 */ |
273 @CallerSensitive |
335 @CallerSensitive |
|
336 @Deprecated |
|
337 @SuppressWarnings("deprecation") |
274 public static Package getPackage(String name) { |
338 public static Package getPackage(String name) { |
275 ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); |
339 ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); |
276 if (l != null) { |
340 return l != null ? l.getPackage(name) : BootLoader.getDefinedPackage(name); |
277 return l.getPackage(name); |
341 } |
278 } else { |
342 |
279 return getSystemPackage(name); |
343 /** |
280 } |
344 * Returns all of the {@code Package}s defined by the caller's class loader |
281 } |
345 * and its ancestors. The returned array may contain more than one |
282 |
346 * {@code Package} object of the same package name, each defined by |
283 /** |
347 * a different class loader in the class loader hierarchy. |
284 * Get all the packages currently known for the caller's {@code ClassLoader} |
348 * <p> |
285 * instance. Those packages correspond to classes loaded via or accessible by |
349 * Calling this method is equivalent to calling {@link ClassLoader#getPackages} |
286 * name to that {@code ClassLoader} instance. If the caller's |
350 * on a {@code ClassLoader} instance which is the caller's class loader. |
287 * {@code ClassLoader} instance is the bootstrap {@code ClassLoader} |
351 * |
288 * instance, which may be represented by {@code null} in some implementations, |
352 * @return The array of {@code Package} objects defined by this |
289 * only packages corresponding to classes loaded by the bootstrap |
353 * class loader and its ancestors |
290 * {@code ClassLoader} instance will be returned. |
354 * |
291 * |
355 * @see ClassLoader#getDefinedPackages |
292 * @return a new array of packages known to the callers {@code ClassLoader} |
|
293 * instance. An zero length array is returned if none are known. |
|
294 */ |
356 */ |
295 @CallerSensitive |
357 @CallerSensitive |
296 public static Package[] getPackages() { |
358 public static Package[] getPackages() { |
297 ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); |
359 ClassLoader cl = ClassLoader.getClassLoader(Reflection.getCallerClass()); |
298 if (l != null) { |
360 return cl != null ? cl.getPackages() : BootLoader.packages().toArray(Package[]::new); |
299 return l.getPackages(); |
|
300 } else { |
|
301 return getSystemPackages(); |
|
302 } |
|
303 } |
|
304 |
|
305 /** |
|
306 * Get the package for the specified class. |
|
307 * The class's class loader is used to find the package instance |
|
308 * corresponding to the specified class. If the class loader |
|
309 * is the bootstrap class loader, which may be represented by |
|
310 * {@code null} in some implementations, then the set of packages |
|
311 * loaded by the bootstrap class loader is searched to find the package. |
|
312 * <p> |
|
313 * Packages have attributes for versions and specifications only |
|
314 * if the class loader created the package |
|
315 * instance with the appropriate attributes. Typically those |
|
316 * attributes are defined in the manifests that accompany |
|
317 * the classes. |
|
318 * |
|
319 * @param c the class to get the package of. |
|
320 * @return the package of the class. It may be null if no package |
|
321 * information is available from the archive or codebase. */ |
|
322 static Package getPackage(Class<?> c) { |
|
323 String name = c.getName(); |
|
324 int i = name.lastIndexOf('.'); |
|
325 if (i != -1) { |
|
326 name = name.substring(0, i); |
|
327 ClassLoader cl = c.getClassLoader(); |
|
328 if (cl != null) { |
|
329 return cl.getPackage(name); |
|
330 } else { |
|
331 return getSystemPackage(name); |
|
332 } |
|
333 } else { |
|
334 return null; |
|
335 } |
|
336 } |
361 } |
337 |
362 |
338 /** |
363 /** |
339 * Return the hash code computed from the package name. |
364 * Return the hash code computed from the package name. |
340 * @return the hash code computed from the package name. |
365 * @return the hash code computed from the package name. |
341 */ |
366 */ |
|
367 @Override |
342 public int hashCode(){ |
368 public int hashCode(){ |
343 return pkgName.hashCode(); |
369 return packageName().hashCode(); |
344 } |
370 } |
345 |
371 |
346 /** |
372 /** |
347 * Returns the string representation of this Package. |
373 * Returns the string representation of this Package. |
348 * Its value is the string "package " and the package name. |
374 * Its value is the string "package " and the package name. |
349 * If the package title is defined it is appended. |
375 * If the package title is defined it is appended. |
350 * If the package version is defined it is appended. |
376 * If the package version is defined it is appended. |
351 * @return the string representation of the package. |
377 * @return the string representation of the package. |
352 */ |
378 */ |
|
379 @Override |
353 public String toString() { |
380 public String toString() { |
354 String spec = specTitle; |
381 String spec = versionInfo.specTitle; |
355 String ver = specVersion; |
382 String ver = versionInfo.specVersion; |
356 if (spec != null && spec.length() > 0) |
383 if (spec != null && spec.length() > 0) |
357 spec = ", " + spec; |
384 spec = ", " + spec; |
358 else |
385 else |
359 spec = ""; |
386 spec = ""; |
360 if (ver != null && ver.length() > 0) |
387 if (ver != null && ver.length() > 0) |
361 ver = ", version " + ver; |
388 ver = ", version " + ver; |
362 else |
389 else |
363 ver = ""; |
390 ver = ""; |
364 return "package " + pkgName + spec + ver; |
391 return "package " + packageName() + spec + ver; |
365 } |
392 } |
366 |
393 |
367 private Class<?> getPackageInfo() { |
394 private Class<?> getPackageInfo() { |
368 if (packageInfo == null) { |
395 if (packageInfo == null) { |
369 try { |
396 // find package-info.class defined by loader |
370 packageInfo = Class.forName(pkgName + ".package-info", false, loader); |
397 String cn = packageName() + ".package-info"; |
371 } catch (ClassNotFoundException ex) { |
398 PrivilegedAction<ClassLoader> pa = module()::getClassLoader; |
|
399 ClassLoader loader = AccessController.doPrivileged(pa); |
|
400 Class<?> c = loader != null ? loader.loadLocalClass(cn) |
|
401 : BootLoader.loadClassOrNull(cn); |
|
402 if (c != null) { |
|
403 packageInfo = c; |
|
404 } else { |
372 // store a proxy for the package info that has no annotations |
405 // store a proxy for the package info that has no annotations |
373 class PackageInfoProxy {} |
406 class PackageInfoProxy {} |
374 packageInfo = PackageInfoProxy.class; |
407 packageInfo = PackageInfoProxy.class; |
375 } |
408 } |
376 } |
409 } |
435 public Annotation[] getDeclaredAnnotations() { |
468 public Annotation[] getDeclaredAnnotations() { |
436 return getPackageInfo().getDeclaredAnnotations(); |
469 return getPackageInfo().getDeclaredAnnotations(); |
437 } |
470 } |
438 |
471 |
439 /** |
472 /** |
440 * Construct a package instance with the specified version |
473 * Construct a package instance for an unnamed module |
441 * information. |
474 * with the specified version information. |
|
475 * |
|
476 * @apiNote |
|
477 * This method should not be called to define a Package for named module. |
|
478 * |
442 * @param name the name of the package |
479 * @param name the name of the package |
443 * @param spectitle the title of the specification |
480 * @param spectitle the title of the specification |
444 * @param specversion the version of the specification |
481 * @param specversion the version of the specification |
445 * @param specvendor the organization that maintains the specification |
482 * @param specvendor the organization that maintains the specification |
446 * @param impltitle the title of the implementation |
483 * @param impltitle the title of the implementation |
447 * @param implversion the version of the implementation |
484 * @param implversion the version of the implementation |
448 * @param implvendor the organization that maintains the implementation |
485 * @param implvendor the organization that maintains the implementation |
|
486 * @param sealbase code source where this Package comes from |
|
487 * @param loader defining class loader |
449 */ |
488 */ |
450 Package(String name, |
489 Package(String name, |
451 String spectitle, String specversion, String specvendor, |
490 String spectitle, String specversion, String specvendor, |
452 String impltitle, String implversion, String implvendor, |
491 String impltitle, String implversion, String implvendor, |
453 URL sealbase, ClassLoader loader) |
492 URL sealbase, ClassLoader loader) |
454 { |
493 { |
455 pkgName = name; |
494 super(Objects.requireNonNull(name), |
456 implTitle = impltitle; |
495 loader != null ? loader.getUnnamedModule() |
457 implVersion = implversion; |
496 : BootLoader.getUnnamedModule()); |
458 implVendor = implvendor; |
497 |
459 specTitle = spectitle; |
498 this.versionInfo = VersionInfo.getInstance(spectitle, specversion, |
460 specVersion = specversion; |
499 specvendor, impltitle, |
461 specVendor = specvendor; |
500 implversion, implvendor, |
462 sealBase = sealbase; |
501 sealbase); |
463 this.loader = loader; |
502 } |
|
503 |
|
504 Package(String name, Module module) { |
|
505 super(name, module); |
|
506 this.versionInfo = VersionInfo.NULL_VERSION_INFO; |
464 } |
507 } |
465 |
508 |
466 /* |
509 /* |
467 * Construct a package using the attributes from the specified manifest. |
510 * Versioning information. Only for packages in unnamed modules. |
468 * |
511 */ |
469 * @param name the package name |
512 static class VersionInfo { |
470 * @param man the optional manifest for the package |
513 static final VersionInfo NULL_VERSION_INFO |
471 * @param url the optional code source url for the package |
514 = new VersionInfo(null, null, null, null, null, null, null); |
472 */ |
515 |
473 private Package(String name, Manifest man, URL url, ClassLoader loader) { |
516 private final String specTitle; |
474 String path = name.replace('.', '/').concat("/"); |
517 private final String specVersion; |
475 String sealed = null; |
518 private final String specVendor; |
476 String specTitle= null; |
519 private final String implTitle; |
477 String specVersion= null; |
520 private final String implVersion; |
478 String specVendor= null; |
521 private final String implVendor; |
479 String implTitle= null; |
522 private final URL sealBase; |
480 String implVersion= null; |
523 |
481 String implVendor= null; |
524 static VersionInfo getInstance(String spectitle, String specversion, |
482 URL sealBase= null; |
525 String specvendor, String impltitle, |
483 Attributes attr = man.getAttributes(path); |
526 String implversion, String implvendor, |
484 if (attr != null) { |
527 URL sealbase) { |
485 specTitle = attr.getValue(Name.SPECIFICATION_TITLE); |
528 if (spectitle == null && specversion == null && |
486 specVersion = attr.getValue(Name.SPECIFICATION_VERSION); |
529 specvendor == null && impltitle == null && |
487 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); |
530 implvendor == null && sealbase == null) { |
488 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); |
531 return NULL_VERSION_INFO; |
489 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); |
|
490 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); |
|
491 sealed = attr.getValue(Name.SEALED); |
|
492 } |
|
493 attr = man.getMainAttributes(); |
|
494 if (attr != null) { |
|
495 if (specTitle == null) { |
|
496 specTitle = attr.getValue(Name.SPECIFICATION_TITLE); |
|
497 } |
532 } |
498 if (specVersion == null) { |
533 return new VersionInfo(spectitle, specversion, specvendor, |
499 specVersion = attr.getValue(Name.SPECIFICATION_VERSION); |
534 impltitle, implversion, implvendor, |
500 } |
535 sealbase); |
501 if (specVendor == null) { |
536 } |
502 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); |
537 |
503 } |
538 private VersionInfo(String spectitle, String specversion, |
504 if (implTitle == null) { |
539 String specvendor, String impltitle, |
505 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); |
540 String implversion, String implvendor, |
506 } |
541 URL sealbase) |
507 if (implVersion == null) { |
542 { |
508 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); |
543 this.implTitle = impltitle; |
509 } |
544 this.implVersion = implversion; |
510 if (implVendor == null) { |
545 this.implVendor = implvendor; |
511 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); |
546 this.specTitle = spectitle; |
512 } |
547 this.specVersion = specversion; |
513 if (sealed == null) { |
548 this.specVendor = specvendor; |
514 sealed = attr.getValue(Name.SEALED); |
549 this.sealBase = sealbase; |
515 } |
550 } |
516 } |
551 } |
517 if ("true".equalsIgnoreCase(sealed)) { |
552 |
518 sealBase = url; |
553 private final VersionInfo versionInfo; |
519 } |
554 private Class<?> packageInfo; |
520 pkgName = name; |
|
521 this.specTitle = specTitle; |
|
522 this.specVersion = specVersion; |
|
523 this.specVendor = specVendor; |
|
524 this.implTitle = implTitle; |
|
525 this.implVersion = implVersion; |
|
526 this.implVendor = implVendor; |
|
527 this.sealBase = sealBase; |
|
528 this.loader = loader; |
|
529 } |
|
530 |
|
531 /* |
|
532 * Returns the loaded system package for the specified name. |
|
533 */ |
|
534 static Package getSystemPackage(String name) { |
|
535 Package pkg = pkgs.get(name); |
|
536 if (pkg == null) { |
|
537 name = name.replace('.', '/').concat("/"); |
|
538 String fn = getSystemPackage0(name); |
|
539 if (fn != null) { |
|
540 pkg = defineSystemPackage(name, fn); |
|
541 } |
|
542 } |
|
543 return pkg; |
|
544 } |
|
545 |
|
546 /* |
|
547 * Return an array of loaded system packages. |
|
548 */ |
|
549 static Package[] getSystemPackages() { |
|
550 // First, update the system package map with new package names |
|
551 String[] names = getSystemPackages0(); |
|
552 for (String name : names) { |
|
553 if (!pkgs.containsKey(name)) { |
|
554 defineSystemPackage(name, getSystemPackage0(name)); |
|
555 } |
|
556 } |
|
557 return pkgs.values().toArray(new Package[pkgs.size()]); |
|
558 } |
|
559 |
|
560 private static Package defineSystemPackage(final String iname, |
|
561 final String fn) |
|
562 { |
|
563 // Convert to "."-separated package name |
|
564 String name = iname.substring(0, iname.length() - 1).replace('/', '.'); |
|
565 // Creates a cached manifest for the file name, allowing |
|
566 // only-once, lazy reads of manifest from jar files |
|
567 CachedManifest cachedManifest = createCachedManifest(fn); |
|
568 pkgs.putIfAbsent(name, new Package(name, cachedManifest.getManifest(), |
|
569 cachedManifest.getURL(), null)); |
|
570 // Ensure we only expose one Package object |
|
571 return pkgs.get(name); |
|
572 } |
|
573 |
|
574 private static CachedManifest createCachedManifest(String fn) { |
|
575 if (!manifests.containsKey(fn)) { |
|
576 manifests.putIfAbsent(fn, new CachedManifest(fn)); |
|
577 } |
|
578 return manifests.get(fn); |
|
579 } |
|
580 |
|
581 // The map of loaded system packages |
|
582 private static final ConcurrentHashMap<String, Package> pkgs |
|
583 = new ConcurrentHashMap<>(); |
|
584 |
|
585 // Maps each directory or zip file name to its corresponding manifest, if |
|
586 // it exists |
|
587 private static final ConcurrentHashMap<String, CachedManifest> manifests |
|
588 = new ConcurrentHashMap<>(); |
|
589 |
|
590 private static class CachedManifest { |
|
591 private static final Manifest EMPTY_MANIFEST = new Manifest(); |
|
592 private final String fileName; |
|
593 private final URL url; |
|
594 private volatile Manifest manifest; |
|
595 |
|
596 CachedManifest(final String fileName) { |
|
597 this.fileName = fileName; |
|
598 this.url = AccessController.doPrivileged(new PrivilegedAction<>() { |
|
599 public URL run() { |
|
600 final File file = new File(fileName); |
|
601 if (file.isFile()) { |
|
602 try { |
|
603 return ParseUtil.fileToEncodedURL(file); |
|
604 } catch (MalformedURLException e) { |
|
605 } |
|
606 } |
|
607 return null; |
|
608 } |
|
609 }); |
|
610 } |
|
611 |
|
612 public URL getURL() { |
|
613 return url; |
|
614 } |
|
615 |
|
616 public Manifest getManifest() { |
|
617 if (url == null) { |
|
618 return EMPTY_MANIFEST; |
|
619 } |
|
620 Manifest m = manifest; |
|
621 if (m != null) { |
|
622 return m; |
|
623 } |
|
624 synchronized (this) { |
|
625 m = manifest; |
|
626 if (m != null) { |
|
627 return m; |
|
628 } |
|
629 m = AccessController.doPrivileged(new PrivilegedAction<>() { |
|
630 public Manifest run() { |
|
631 try (FileInputStream fis = new FileInputStream(fileName); |
|
632 JarInputStream jis = new JarInputStream(fis, false)) { |
|
633 return jis.getManifest(); |
|
634 } catch (IOException e) { |
|
635 return null; |
|
636 } |
|
637 } |
|
638 }); |
|
639 manifest = m = (m == null ? EMPTY_MANIFEST : m); |
|
640 } |
|
641 return m; |
|
642 } |
|
643 } |
|
644 |
|
645 private static native String getSystemPackage0(String name); |
|
646 private static native String[] getSystemPackages0(); |
|
647 |
|
648 /* |
|
649 * Private storage for the package name and attributes. |
|
650 */ |
|
651 private final String pkgName; |
|
652 private final String specTitle; |
|
653 private final String specVersion; |
|
654 private final String specVendor; |
|
655 private final String implTitle; |
|
656 private final String implVersion; |
|
657 private final String implVendor; |
|
658 private final URL sealBase; |
|
659 private final transient ClassLoader loader; |
|
660 private transient Class<?> packageInfo; |
|
661 } |
555 } |