1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 /*
18  * Copyright (C) 2008 The Android Open Source Project
19  *
20  * Licensed under the Apache License, Version 2.0 (the "License");
21  * you may not use this file except in compliance with the License.
22  * You may obtain a copy of the License at
23  *
24  *      http://www.apache.org/licenses/LICENSE-2.0
25  *
26  * Unless required by applicable law or agreed to in writing, software
27  * distributed under the License is distributed on an "AS IS" BASIS,
28  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29  * See the License for the specific language governing permissions and
30  * limitations under the License.
31  */
32 
33 package java.lang;
34 
35 import dalvik.system.VMStack;
36 import java.lang.annotation.Annotation;
37 import java.lang.reflect.AnnotatedElement;
38 import java.net.URL;
39 
40 /**
41  * Contains information about a Java package. This includes implementation and
42  * specification versions. Typically this information is retrieved from the
43  * manifest.
44  * <p>
45  * Packages are managed by class loaders. All classes loaded by the same loader
46  * from the same package share a {@code Package} instance.
47  * </p>
48  *
49  * @see java.lang.ClassLoader
50  */
51 public class Package implements AnnotatedElement {
52     private static final Annotation[] NO_ANNOTATIONS = new Annotation[0];
53 
54     private final String name;
55     private final String specTitle;
56     private final String specVersion;
57     private final String specVendor;
58     private final String implTitle;
59     private final String implVersion;
60     private final String implVendor;
61     private final URL sealBase;
62 
Package(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase)63     Package(String name, String specTitle, String specVersion, String specVendor,
64             String implTitle, String implVersion, String implVendor, URL sealBase) {
65         this.name = name;
66         this.specTitle = specTitle;
67         this.specVersion = specVersion;
68         this.specVendor = specVendor;
69         this.implTitle = implTitle;
70         this.implVersion = implVersion;
71         this.implVendor = implVendor;
72         this.sealBase = sealBase;
73     }
74 
75     /**
76      * Returns the annotation associated with the specified annotation type and
77      * this package, if present.
78      *
79      * @param annotationType
80      *            the annotation type to look for.
81      * @return an instance of {@link Annotation} or {@code null}.
82      * @see java.lang.reflect.AnnotatedElement#getAnnotation(java.lang.Class)
83      */
84     @SuppressWarnings("unchecked")
getAnnotation(Class<A> annotationType)85     public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
86         for (Annotation annotation : getAnnotations()) {
87             if (annotationType.isInstance(annotation)) {
88                 return (A) annotation;
89             }
90         }
91         return null;
92     }
93 
94     /**
95      * Returns an array of this package's annotations.
96      */
getAnnotations()97     public Annotation[] getAnnotations() {
98         try {
99             Class<?> c = Class.forName(getName() + ".package-info");
100             return c.getAnnotations();
101         } catch (Exception ex) {
102             return NO_ANNOTATIONS;
103         }
104     }
105 
106     /**
107      * Returns an array of this package's declared annotations. Package annotations aren't
108      * inherited, so this is equivalent to {@link #getAnnotations}.
109      */
getDeclaredAnnotations()110     public Annotation[] getDeclaredAnnotations() {
111         return getAnnotations();
112     }
113 
114     /**
115      * Indicates whether the specified annotation is present.
116      *
117      * @param annotationType
118      *            the annotation type to look for.
119      * @return {@code true} if the annotation is present; {@code false}
120      *         otherwise.
121      * @see java.lang.reflect.AnnotatedElement#isAnnotationPresent(java.lang.Class)
122      */
isAnnotationPresent(Class<? extends Annotation> annotationType)123     public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
124         return getAnnotation(annotationType) != null;
125     }
126 
127     /**
128      * Returns the title of the implementation of this package, or {@code null}
129      * if this is unknown. The format of this string is unspecified.
130      *
131      * @return the implementation title, may be {@code null}.
132      */
getImplementationTitle()133     public String getImplementationTitle() {
134         return implTitle;
135     }
136 
137     /**
138      * Returns the name of the vendor or organization that provides this
139      * implementation of the package, or {@code null} if this is unknown. The
140      * format of this string is unspecified.
141      *
142      * @return the implementation vendor name, may be {@code null}.
143      */
getImplementationVendor()144     public String getImplementationVendor() {
145         return implVendor;
146     }
147 
148     /**
149      * Returns the version of the implementation of this package, or {@code
150      * null} if this is unknown. The format of this string is unspecified.
151      *
152      * @return the implementation version, may be {@code null}.
153      */
getImplementationVersion()154     public String getImplementationVersion() {
155         return implVersion;
156     }
157 
158     /**
159      * Returns the name of this package in the standard dot notation; for
160      * example: "java.lang".
161      *
162      * @return the name of this package.
163      */
getName()164     public String getName() {
165         return name;
166     }
167 
168     /**
169      * Attempts to locate the requested package in the caller's class loader. If
170      * no package information can be located, {@code null} is returned.
171      *
172      * @param packageName
173      *            the name of the package to find.
174      * @return the requested package, or {@code null}.
175      * @see ClassLoader#getPackage(java.lang.String)
176      */
getPackage(String packageName)177     public static Package getPackage(String packageName) {
178         ClassLoader classloader = VMStack.getCallingClassLoader();
179         if (classloader == null) {
180             classloader = ClassLoader.getSystemClassLoader();
181         }
182         return classloader.getPackage(packageName);
183     }
184 
185     /**
186      * Returns all the packages known to the caller's class loader.
187      *
188      * @return all the packages known to the caller's class loader.
189      * @see ClassLoader#getPackages
190      */
getPackages()191     public static Package[] getPackages() {
192         ClassLoader classloader = VMStack.getCallingClassLoader();
193         if (classloader == null) {
194             classloader = ClassLoader.getSystemClassLoader();
195         }
196         return classloader.getPackages();
197     }
198 
199     /**
200      * Returns the title of the specification this package implements, or
201      * {@code null} if this is unknown.
202      *
203      * @return the specification title, may be {@code null}.
204      */
getSpecificationTitle()205     public String getSpecificationTitle() {
206         return specTitle;
207     }
208 
209     /**
210      * Returns the name of the vendor or organization that owns and maintains
211      * the specification this package implements, or {@code null} if this is
212      * unknown.
213      *
214      * @return the specification vendor name, may be {@code null}.
215      */
getSpecificationVendor()216     public String getSpecificationVendor() {
217         return specVendor;
218     }
219 
220     /**
221      * Returns the version of the specification this package implements, or
222      * {@code null} if this is unknown. The version string is a sequence of
223      * non-negative integers separated by dots; for example: "1.2.3".
224      *
225      * @return the specification version string, may be {@code null}.
226      */
getSpecificationVersion()227     public String getSpecificationVersion() {
228         return specVersion;
229     }
230 
231     @Override
hashCode()232     public int hashCode() {
233         return name.hashCode();
234     }
235 
236     /**
237      * Indicates whether this package's specification version is compatible with
238      * the specified version string. Version strings are compared by comparing
239      * each dot separated part of the version as an integer.
240      *
241      * @param version
242      *            the version string to compare against.
243      * @return {@code true} if the package versions are compatible; {@code
244      *         false} otherwise.
245      * @throws NumberFormatException
246      *             if this package's version string or the one provided are not
247      *             in the correct format.
248      */
isCompatibleWith(String version)249     public boolean isCompatibleWith(String version) throws NumberFormatException {
250         String[] requested = version.split("\\.");
251         String[] provided = specVersion.split("\\.");
252 
253         for (int i = 0; i < Math.min(requested.length, provided.length); i++) {
254             int reqNum = Integer.parseInt(requested[i]);
255             int provNum = Integer.parseInt(provided[i]);
256 
257             if (reqNum > provNum) {
258                 return false;
259             } else if (reqNum < provNum) {
260                 return true;
261             }
262         }
263 
264         if (requested.length > provided.length) {
265             return false;
266         }
267 
268         return true;
269     }
270 
271     /**
272      * Indicates whether this package is sealed.
273      *
274      * @return {@code true} if this package is sealed; {@code false} otherwise.
275      */
isSealed()276     public boolean isSealed() {
277         return sealBase != null;
278     }
279 
280     /**
281      * Indicates whether this package is sealed with respect to the specified
282      * URL.
283      *
284      * @param url
285      *            the URL to check.
286      * @return {@code true} if this package is sealed with {@code url}; {@code
287      *         false} otherwise
288      */
isSealed(URL url)289     public boolean isSealed(URL url) {
290         return sealBase != null && sealBase.sameFile(url);
291     }
292 
293     @Override
toString()294     public String toString() {
295         return "package " + name;
296     }
297 }
298