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; 36import java.lang.annotation.Annotation; 37import java.lang.reflect.AnnotatedElement; 38import 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 */ 51public 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 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") 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 227 public String getSpecificationVersion() { 228 return specVersion; 229 } 230 231 @Override 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 */ 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 */ 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 */ 289 public boolean isSealed(URL url) { 290 return sealBase != null && sealBase.sameFile(url); 291 } 292 293 @Override 294 public String toString() { 295 return "package " + name; 296 } 297} 298