1 /* Package.java -- information about a package
2    Copyright (C) 2000, 2001, 2002, 2003, 2005, 2006
3    Free Software Foundation, Inc.
4 
5 This file is part of GNU Classpath.
6 
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21 
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26 
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 package java.lang;
40 
41 import gnu.classpath.VMStackWalker;
42 
43 import java.lang.annotation.Annotation;
44 import java.lang.reflect.AnnotatedElement;
45 import java.net.URL;
46 import java.util.NoSuchElementException;
47 import java.util.StringTokenizer;
48 
49 
50 /**
51  * Everything you ever wanted to know about a package. This class makes it
52  * possible to attach specification and implementation information to a
53  * package as explained in the
54  * <a href="http://java.sun.com/products/jdk/1.3/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersionSpecification">Package Versioning Specification</a>
55  * section of the
56  * <a href="http://java.sun.com/products/jdk/1.3/docs/guide/versioning/spec/VersioningSpecification.html">Product Versioning Specification</a>.
57  * It also allows packages to be sealed with respect to the originating URL.
58  *
59  * <p>The most useful method is the <code>isCompatibleWith()</code> method that
60  * compares a desired version of a specification with the version of the
61  * specification as implemented by a package. A package is considered
62  * compatible with another version if the version of the specification is
63  * equal or higher then the requested version. Version numbers are represented
64  * as strings of positive numbers separated by dots (e.g. "1.2.0").
65  * The first number is called the major number, the second the minor,
66  * the third the micro, etc. A version is considered higher then another
67  * version if it has a bigger major number then the another version or when
68  * the major numbers of the versions are equal if it has a bigger minor number
69  * then the other version, etc. (If a version has no minor, micro, etc numbers
70  * then they are considered the be 0.)
71  *
72  * @author Mark Wielaard (mark@klomp.org)
73  * @see ClassLoader#definePackage(String, String, String, String, String,
74  *      String, String, URL)
75  * @since 1.2
76  * @status updated to 1.5
77  */
78 public class Package
79   implements AnnotatedElement
80 {
81   /** The name of the Package */
82   private final String name;
83 
84   /** The name if the implementation */
85   private final String implTitle;
86 
87   /** The vendor that wrote this implementation */
88   private final String implVendor;
89 
90   /** The version of this implementation */
91   private final String implVersion;
92 
93   /** The name of the specification */
94   private final String specTitle;
95 
96   /** The name of the specification designer */
97   private final String specVendor;
98 
99   /** The version of this specification */
100   private final String specVersion;
101 
102   /** If sealed the origin of the package classes, otherwise null */
103   private final URL sealed;
104 
105   /** The class loader that defined this package */
106   private ClassLoader loader;
107 
108   /** @deprecated Please use the other constructor that takes the class loader
109    *              that defines the Package.
110    */
Package(String name, String specTitle, String specVendor, String specVersion, String implTitle, String implVendor, String implVersion, URL sealed)111   Package(String name,
112           String specTitle, String specVendor, String specVersion,
113           String implTitle, String implVendor, String implVersion, URL sealed)
114   {
115     this(name, specTitle, specVendor, specVersion, implTitle, implVendor,
116          implVersion, sealed, null);
117   }
118 
119   /**
120    * A package local constructor for the Package class. All parameters except
121    * the <code>name</code> of the package may be <code>null</code>.
122    * There are no public constructors defined for Package; this is a package
123    * local constructor that is used by java.lang.Classloader.definePackage().
124    *
125    * @param name The name of the Package
126    * @param specTitle The name of the specification
127    * @param specVendor The name of the specification designer
128    * @param specVersion The version of this specification
129    * @param implTitle The name of the implementation
130    * @param implVendor The vendor that wrote this implementation
131    * @param implVersion The version of this implementation
132    * @param sealed If sealed the origin of the package classes
133    */
Package(String name, String specTitle, String specVendor, String specVersion, String implTitle, String implVendor, String implVersion, URL sealed, ClassLoader loader)134   Package(String name,
135           String specTitle, String specVendor, String specVersion,
136           String implTitle, String implVendor, String implVersion, URL sealed,
137           ClassLoader loader)
138   {
139     if (name == null)
140       throw new IllegalArgumentException("null Package name");
141 
142     this.name = name;
143     this.implTitle = implTitle;
144     this.implVendor = implVendor;
145     this.implVersion = implVersion;
146     this.specTitle = specTitle;
147     this.specVendor = specVendor;
148     this.specVersion = specVersion;
149     this.sealed = sealed;
150     this.loader = loader;
151   }
152 
153   /**
154    * Returns the Package name in dot-notation.
155    *
156    * @return the non-null package name
157    */
getName()158   public String getName()
159   {
160     return name;
161   }
162 
163   /**
164    * Returns the name of the specification, or null if unknown.
165    *
166    * @return the specification title
167    */
getSpecificationTitle()168   public String getSpecificationTitle()
169   {
170     return specTitle;
171   }
172 
173   /**
174    * Returns the version of the specification, or null if unknown.
175    *
176    * @return the specification version
177    */
getSpecificationVersion()178   public String getSpecificationVersion()
179   {
180     return specVersion;
181   }
182 
183   /**
184    * Returns the name of the specification designer, or null if unknown.
185    *
186    * @return the specification vendor
187    */
getSpecificationVendor()188   public String getSpecificationVendor()
189   {
190     return specVendor;
191   }
192 
193   /**
194    * Returns the name of the implementation, or null if unknown.
195    *
196    * @return the implementation title
197    */
getImplementationTitle()198   public String getImplementationTitle()
199   {
200     return implTitle;
201   }
202 
203   /**
204    * Returns the version of this implementation, or null if unknown.
205    *
206    * @return the implementation version
207    */
getImplementationVersion()208   public String getImplementationVersion()
209   {
210     return implVersion;
211   }
212 
213   /**
214    * Returns the vendor that wrote this implementation, or null if unknown.
215    *
216    * @return the implementation vendor
217    */
getImplementationVendor()218   public String getImplementationVendor()
219   {
220     return implVendor;
221   }
222 
223   /**
224    * Returns true if this Package is sealed.
225    *
226    * @return true if the package is sealed
227    */
isSealed()228   public boolean isSealed()
229   {
230     return sealed != null;
231   }
232 
233   /**
234    * Returns true if this Package is sealed and the origin of the classes is
235    * the given URL.
236    *
237    * @param url the URL to test
238    * @return true if the package is sealed by this URL
239    * @throws NullPointerException if url is null
240    */
isSealed(URL url)241   public boolean isSealed(URL url)
242   {
243     return url.equals(sealed);
244   }
245 
246   /**
247    * Checks if the version of the specification is higher or at least as high
248    * as the desired version. Comparison is done by sequentially comparing
249    * dotted decimal numbers from the parameter and from
250    * <code>getSpecificationVersion</code>.
251    *
252    * @param version the (minimal) desired version of the specification
253    *
254    * @return true if the version is compatible, false otherwise
255    *
256    * @throws NumberFormatException if either version string is invalid
257    * @throws NullPointerException if either version string is null
258    */
isCompatibleWith(String version)259   public boolean isCompatibleWith(String version)
260   {
261     StringTokenizer versionTokens = new StringTokenizer(version, ".");
262     StringTokenizer specTokens = new StringTokenizer(specVersion, ".");
263     try
264       {
265         while (versionTokens.hasMoreElements())
266           {
267             int vers = Integer.parseInt(versionTokens.nextToken());
268             int spec = Integer.parseInt(specTokens.nextToken());
269             if (spec < vers)
270               return false;
271             else if (spec > vers)
272               return true;
273             // They must be equal, next Token please!
274           }
275       }
276     catch (NoSuchElementException e)
277       {
278         // This must have been thrown by spec.nextToken() so return false.
279         return false;
280       }
281     // They must have been exactly the same version.
282     // Or the specVersion has more subversions. That is also good.
283     return true;
284   }
285 
286   /**
287    * Returns the named package if it is known by the callers class loader.
288    * It may return null if the package is unknown, when there is no
289    * information on that particular package available or when the callers
290    * classloader is null.
291    *
292    * @param name the name of the desired package
293    * @return the package by that name in the current ClassLoader
294    */
getPackage(String name)295   public static Package getPackage(String name)
296   {
297     // Get the caller's classloader
298     ClassLoader cl = VMStackWalker.getCallingClassLoader();
299     return cl != null ? cl.getPackage(name) : VMClassLoader.getPackage(name);
300   }
301 
302   /**
303    * Returns all the packages that are known to the callers class loader.
304    * It may return an empty array if the classloader of the caller is null.
305    *
306    * @return an array of all known packages
307    */
getPackages()308   public static Package[] getPackages()
309   {
310     // Get the caller's classloader
311     ClassLoader cl = VMStackWalker.getCallingClassLoader();
312     return cl != null ? cl.getPackages() : VMClassLoader.getPackages();
313   }
314 
315   /**
316    * Returns the hashCode of the name of this package.
317    *
318    * @return the hash code
319    */
hashCode()320   public int hashCode()
321   {
322     return name.hashCode();
323   }
324 
325   /**
326    * Returns a string representation of this package. It is specified to
327    * be <code>"package " + getName() + (getSpecificationTitle() == null
328    * ? "" : ", " + getSpecificationTitle()) + (getSpecificationVersion()
329    * == null ? "" : ", version " + getSpecificationVersion())</code>.
330    *
331    * @return the string representation of the package
332    */
toString()333   public String toString()
334   {
335     return ("package " + name + (specTitle == null ? "" : ", " + specTitle)
336             + (specVersion == null ? "" : ", version " + specVersion));
337   }
338 
339   /**
340    * Returns this package's annotation for the specified annotation type,
341    * or <code>null</code> if no such annotation exists.
342    *
343    * @param annotationClass the type of annotation to look for.
344    * @return this package's annotation for the specified type, or
345    *         <code>null</code> if no such annotation exists.
346    * @since 1.5
347    */
getAnnotation(Class<A> annotationClass)348   public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
349   {
350     A foundAnnotation = null;
351     Annotation[] annotations = getAnnotations();
352     for (Annotation annotation : annotations)
353       if (annotation.annotationType() == annotationClass)
354         foundAnnotation = (A) annotation;
355     return foundAnnotation;
356   }
357 
358   /**
359    * Returns all annotations associated with this package.  If there are
360    * no annotations associated with this package, then a zero-length array
361    * will be returned.  The returned array may be modified by the client
362    * code, but this will have no effect on the annotation content of this
363    * package, and hence no effect on the return value of this method for
364    * future callers.
365    *
366    * @return this package' annotations.
367    * @since 1.5
368    */
getAnnotations()369   public Annotation[] getAnnotations()
370   {
371     /** All a package's annotations are declared within it. */
372     return getDeclaredAnnotations();
373   }
374 
375   /**
376    * Returns all annotations directly defined by this package.  If there are
377    * no annotations associated with this package, then a zero-length array
378    * will be returned.  The returned array may be modified by the client
379    * code, but this will have no effect on the annotation content of this
380    * package, and hence no effect on the return value of this method for
381    * future callers.
382    *
383    * @return the annotations directly defined by this package.
384    * @since 1.5
385    */
getDeclaredAnnotations()386   public Annotation[] getDeclaredAnnotations()
387   {
388     try
389       {
390         Class pkgInfo = Class.forName(name + ".package-info", false, loader);
391         return pkgInfo.getDeclaredAnnotations();
392       }
393     catch (ClassNotFoundException _)
394       {
395         return new Annotation[0];
396       }
397   }
398 
399   /**
400    * Returns true if an annotation for the specified type is associated
401    * with this package.  This is primarily a short-hand for using marker
402    * annotations.
403    *
404    * @param annotationClass the type of annotation to look for.
405    * @return true if an annotation exists for the specified type.
406    * @since 1.5
407    */
isAnnotationPresent(Class<? extends Annotation> annotationClass)408   public boolean isAnnotationPresent(Class<? extends Annotation>
409                                      annotationClass)
410   {
411     return getAnnotation(annotationClass) != null;
412   }
413 
414 } // class Package
415