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
33package java.lang;
34
35import dalvik.system.VMStack;
36
37import java.lang.annotation.Annotation;
38import java.lang.reflect.AnnotatedElement;
39import java.net.URL;
40
41/**
42 * Contains information about a Java package. This includes implementation and
43 * specification versions. Typically this information is retrieved from the
44 * manifest.
45 * <p>
46 * Packages are managed by class loaders. All classes loaded by the same loader
47 * from the same package share a {@code Package} instance.
48 * </p>
49 * @since Android 1.0
50 *
51 * @see java.lang.ClassLoader
52 */
53public class Package implements AnnotatedElement {
54
55    private final String name, specTitle, specVersion, specVendor, implTitle,
56            implVersion, implVendor;
57    private final URL sealBase;
58
59    Package(String name, String specTitle, String specVersion, String specVendor,
60            String implTitle, String implVersion, String implVendor, URL sealBase) {
61        this.name = name;
62        this.specTitle = specTitle;
63        this.specVersion = specVersion;
64        this.specVendor = specVendor;
65        this.implTitle = implTitle;
66        this.implVersion = implVersion;
67        this.implVendor = implVendor;
68        this.sealBase = sealBase;
69    }
70
71    /**
72     * Gets the annotation associated with the specified annotation type and
73     * this package, if present.
74     *
75     * @param annotationType
76     *            the annotation type to look for.
77     * @return an instance of {@link Annotation} or {@code null}.
78     * @see java.lang.reflect.AnnotatedElement#getAnnotation(java.lang.Class)
79     * @since Android 1.0
80     */
81    @SuppressWarnings("unchecked")
82    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
83        Annotation[] list = getAnnotations();
84        for (int i = 0; i < list.length; i++) {
85            if (annotationType.isInstance(list[i])) {
86                return (T)list[i];
87            }
88        }
89
90        return null;
91    }
92
93    /**
94     * Gets all annotations associated with this package, if any.
95     *
96     * @return an array of {@link Annotation} instances, which may be empty.
97     * @see java.lang.reflect.AnnotatedElement#getAnnotations()
98     * @since Android 1.0
99     */
100    public Annotation[] getAnnotations() {
101        return getDeclaredAnnotations(this, true);
102    }
103
104    /**
105     * Gets all annotations directly declared on this package, if any.
106     *
107     * @return an array of {@link Annotation} instances, which may be empty.
108     * @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotations()
109     * @since Android 1.0
110     */
111    public Annotation[] getDeclaredAnnotations() {
112        return getDeclaredAnnotations(this, false);
113    }
114
115    /*
116     * Returns the list of declared annotations of the given package.
117     * If no annotations exist, an empty array is returned.
118     *
119     * @param pkg the package of interest
120     * @param publicOnly reflects whether we want only public annotation or all
121     * of them.
122     * @return the list of annotations
123     */
124    // TODO(Google) Provide proper (native) implementation.
125    private static native Annotation[] getDeclaredAnnotations(Package pkg,
126            boolean publicOnly);
127
128    /**
129     * Indicates whether the specified annotation is present.
130     *
131     * @param annotationType
132     *            the annotation type to look for.
133     * @return {@code true} if the annotation is present; {@code false}
134     *         otherwise.
135     * @see java.lang.reflect.AnnotatedElement#isAnnotationPresent(java.lang.Class)
136     * @since Android 1.0
137     */
138    public boolean isAnnotationPresent(
139            Class<? extends Annotation> annotationType) {
140        return getAnnotation(annotationType) != null;
141    }
142
143    /**
144     * Returns the title of the implementation of this package, or {@code null}
145     * if this is unknown. The format of this string is unspecified.
146     *
147     * @return the implementation title, may be {@code null}.
148     * @since Android 1.0
149     */
150    public String getImplementationTitle() {
151        return implTitle;
152    }
153
154    /**
155     * Returns the name of the vendor or organization that provides this
156     * implementation of the package, or {@code null} if this is unknown. The
157     * format of this string is unspecified.
158     *
159     * @return the implementation vendor name, may be {@code null}.
160     * @since Android 1.0
161     */
162    public String getImplementationVendor() {
163        return implVendor;
164    }
165
166    /**
167     * Returns the version of the implementation of this package, or {@code
168     * null} if this is unknown. The format of this string is unspecified.
169     *
170     * @return the implementation version, may be {@code null}.
171     * @since Android 1.0
172     */
173    public String getImplementationVersion() {
174        return implVersion;
175    }
176
177    /**
178     * Returns the name of this package in the standard dot notation; for
179     * example: "java.lang".
180     *
181     * @return the name of this package.
182     * @since Android 1.0
183     */
184    public String getName() {
185        return name;
186    }
187
188    /**
189     * Attempts to locate the requested package in the caller's class loader. If
190     * no package information can be located, {@code null} is returned.
191     *
192     * @param packageName
193     *            the name of the package to find.
194     * @return the requested package, or {@code null}.
195     * @see ClassLoader#getPackage(java.lang.String)
196     * @since Android 1.0
197     */
198    public static Package getPackage(String packageName) {
199        ClassLoader classloader = VMStack.getCallingClassLoader();
200        return classloader.getPackage(packageName);
201    }
202
203    /**
204     * Returns all the packages known to the caller's class loader.
205     *
206     * @return all the packages known to the caller's class loader.
207     * @see ClassLoader#getPackages
208     * @since Android 1.0
209     */
210    public static Package[] getPackages() {
211        ClassLoader classloader = VMStack.getCallingClassLoader();
212        return classloader.getPackages();
213    }
214
215    /**
216     * Returns the title of the specification this package implements, or
217     * {@code null} if this is unknown.
218     *
219     * @return the specification title, may be {@code null}.
220     * @since Android 1.0
221     */
222    public String getSpecificationTitle() {
223        return specTitle;
224    }
225
226    /**
227     * Returns the name of the vendor or organization that owns and maintains
228     * the specification this package implements, or {@code null} if this is
229     * unknown.
230     *
231     * @return the specification vendor name, may be {@code null}.
232     * @since Android 1.0
233     */
234    public String getSpecificationVendor() {
235        return specVendor;
236    }
237
238    /**
239     * Returns the version of the specification this package implements, or
240     * {@code null} if this is unknown. The version string is a sequence of
241     * non-negative integers separated by dots; for example: "1.2.3".
242     *
243     * @return the specification version string, may be {@code null}.
244     * @since Android 1.0
245     */
246    public String getSpecificationVersion() {
247        return specVersion;
248    }
249
250    @Override
251    public int hashCode() {
252        return name.hashCode();
253    }
254
255    /**
256     * Indicates whether this package's specification version is compatible with
257     * the specified version string. Version strings are compared by comparing
258     * each dot separated part of the version as an integer.
259     *
260     * @param version
261     *            the version string to compare against.
262     * @return {@code true} if the package versions are compatible; {@code
263     *         false} otherwise.
264     * @throws NumberFormatException
265     *             if this package's version string or the one provided are not
266     *             in the correct format.
267     * @since Android 1.0
268     */
269    public boolean isCompatibleWith(String version)
270            throws NumberFormatException {
271        String[] requested = version.split(".");
272        String[] provided = specVersion.split(".");
273
274        for (int i = 0; i < Math.min(requested.length, provided.length); i++) {
275            int reqNum = Integer.parseInt(requested[i]);
276            int provNum = Integer.parseInt(provided[i]);
277
278            if (reqNum > provNum) {
279                return false;
280            } else if (reqNum < provNum) {
281                return true;
282            }
283        }
284
285        if (requested.length > provided.length) {
286            return false;
287        }
288
289        return true;
290    }
291
292    /**
293     * Indicates whether this package is sealed.
294     *
295     * @return {@code true} if this package is sealed; {@code false} otherwise.
296     * @since Android 1.0
297     */
298    public boolean isSealed() {
299        return sealBase != null;
300    }
301
302    /**
303     * Indicates whether this package is sealed with respect to the specified
304     * URL.
305     *
306     * @param url
307     *            the URL to check.
308     * @return {@code true} if this package is sealed with {@code url}; {@code
309     *         false} otherwise
310     * @since Android 1.0
311     */
312    public boolean isSealed(URL url) {
313        return sealBase != null && sealBase.sameFile(url);
314    }
315
316    @Override
317    public String toString() {
318        return "package " + name;
319    }
320}
321
322