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 package java.util.jar; 19 20 import java.util.Collection; 21 import java.util.HashMap; 22 import java.util.Map; 23 import java.util.Set; 24 25 import org.apache.harmony.archive.util.Util; 26 27 /** 28 * The {@code Attributes} class is used to store values for manifest entries. 29 * Attribute keys are generally instances of {@code Attributes.Name}. Values 30 * associated with attribute keys are of type {@code String}. 31 * @since Android 1.0 32 */ 33 public class Attributes implements Cloneable, Map<Object, Object> { 34 35 /** 36 * The {@code Attributes} as name/value pairs. Maps the attribute names (as 37 * {@link Attributes.Name}) of a JAR file manifest to arbitrary values. The 38 * attribute names thus are obtained from the {@link Manifest} for 39 * convenience. 40 * 41 * @since Android 1.0 42 */ 43 protected Map<Object, Object> map; 44 45 /** 46 * The name part of the name/value pairs constituting an attribute as 47 * defined by the specification of the JAR manifest. May be composed of the 48 * following ASCII signs as defined in the EBNF below: 49 * 50 * <pre> 51 * name = alphanum *headerchar 52 * headerchar = alphanum | - | _ 53 * alphanum = {A-Z} | {a-z} | {0-9} 54 * </pre> 55 * 56 * @since Android 1.0 57 */ 58 public static class Name { 59 private final String name; 60 61 private int hashCode; 62 63 /** 64 * The class path (a main attribute). 65 * 66 * @since Android 1.0 67 */ 68 public static final Name CLASS_PATH = new Name("Class-Path"); //$NON-NLS-1$ 69 70 /** 71 * The version of the manifest file (a main attribute). 72 * 73 * @since Android 1.0 74 */ 75 public static final Name MANIFEST_VERSION = new Name( 76 "Manifest-Version"); //$NON-NLS-1$ 77 78 /** 79 * The main class's name (for stand-alone applications). 80 * 81 * @since Android 1.0 82 */ 83 public static final Name MAIN_CLASS = new Name("Main-Class"); //$NON-NLS-1$ 84 85 /** 86 * Defines the signature version of the JAR file. 87 * 88 * @since Android 1.0 89 */ 90 public static final Name SIGNATURE_VERSION = new Name( 91 "Signature-Version"); //$NON-NLS-1$ 92 93 /** 94 * The {@code Content-Type} manifest attribute. 95 */ 96 public static final Name CONTENT_TYPE = new Name("Content-Type"); //$NON-NLS-1$ 97 98 /** 99 * The {@code Sealed} manifest attribute which may have the value 100 * {@code true} for sealed archives. 101 * 102 * @since Android 1.0 103 */ 104 public static final Name SEALED = new Name("Sealed"); //$NON-NLS-1$ 105 106 /** 107 * The {@code Implementation-Title} attribute whose value is a string 108 * that defines the title of the extension implementation. 109 * 110 * @since Android 1.0 111 */ 112 public static final Name IMPLEMENTATION_TITLE = new Name( 113 "Implementation-Title"); //$NON-NLS-1$ 114 115 /** 116 * The {@code Implementation-Version} attribute defining the version of 117 * the extension implementation. 118 * 119 * @since Android 1.0 120 */ 121 public static final Name IMPLEMENTATION_VERSION = new Name( 122 "Implementation-Version"); //$NON-NLS-1$ 123 124 /** 125 * The {@code Implementation-Vendor} attribute defining the organization 126 * that maintains the extension implementation. 127 * 128 * @since Android 1.0 129 */ 130 public static final Name IMPLEMENTATION_VENDOR = new Name( 131 "Implementation-Vendor"); //$NON-NLS-1$ 132 133 /** 134 * The {@code Specification-Title} attribute defining the title of the 135 * extension specification. 136 * 137 * @since Android 1.0 138 */ 139 public static final Name SPECIFICATION_TITLE = new Name( 140 "Specification-Title"); //$NON-NLS-1$ 141 142 /** 143 * The {@code Specification-Version} attribute defining the version of 144 * the extension specification. 145 * 146 * @since Android 1.0 147 */ 148 public static final Name SPECIFICATION_VERSION = new Name( 149 "Specification-Version"); //$NON-NLS-1$ 150 151 /** 152 * The {@code Specification-Vendor} attribute defining the organization 153 * that maintains the extension specification. 154 * 155 * @since Android 1.0 156 */ 157 public static final Name SPECIFICATION_VENDOR = new Name( 158 "Specification-Vendor"); //$NON-NLS-1$ 159 160 /** 161 * The {@code Extension-List} attribute defining the extensions that are 162 * needed by the applet. 163 * 164 * @since Android 1.0 165 */ 166 public static final Name EXTENSION_LIST = new Name("Extension-List"); //$NON-NLS-1$ 167 168 /** 169 * The {@code Extension-Name} attribute which defines the unique name of 170 * the extension. 171 * 172 * @since Android 1.0 173 */ 174 public static final Name EXTENSION_NAME = new Name("Extension-Name"); //$NON-NLS-1$ 175 176 /** 177 * The {@code Extension-Installation} attribute. 178 * 179 * @since Android 1.0 180 */ 181 public static final Name EXTENSION_INSTALLATION = new Name( 182 "Extension-Installation"); //$NON-NLS-1$ 183 184 /** 185 * The {@code Implementation-Vendor-Id} attribute specifies the vendor 186 * of an extension implementation if the applet requires an 187 * implementation from a specific vendor. 188 * 189 * @since Android 1.0 190 */ 191 public static final Name IMPLEMENTATION_VENDOR_ID = new Name( 192 "Implementation-Vendor-Id"); //$NON-NLS-1$ 193 194 /** 195 * The {@code Implementation-URL} attribute specifying a URL that can be 196 * used to obtain the most recent version of the extension if the 197 * required version is not already installed. 198 * 199 * @since Android 1.0 200 */ 201 public static final Name IMPLEMENTATION_URL = new Name( 202 "Implementation-URL"); //$NON-NLS-1$ 203 204 /** 205 * A String which must satisfy the following EBNF grammar to specify an 206 * additional attribute: 207 * 208 * <pre> 209 * name = alphanum *headerchar 210 * headerchar = alphanum | - | _ 211 * alphanum = {A-Z} | {a-z} | {0-9} 212 * </pre> 213 * 214 * @param s 215 * The Attribute string. 216 * @exception IllegalArgumentException 217 * if the string does not satisfy the EBNF grammar. 218 * @since Android 1.0 219 */ Name(String s)220 public Name(String s) { 221 int i = s.length(); 222 if (i == 0 || i > 70) { 223 throw new IllegalArgumentException(); 224 } 225 for (; --i >= 0;) { 226 char ch = s.charAt(i); 227 if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') 228 || ch == '_' || ch == '-' || (ch >= '0' && ch <= '9'))) { 229 throw new IllegalArgumentException(s); 230 } 231 } 232 name = s; 233 } 234 235 /** 236 * Returns this attribute name. 237 * 238 * @return the attribute name. 239 * @since Android 1.0 240 */ 241 @Override toString()242 public String toString() { 243 return name; 244 } 245 246 /** 247 * returns whether the argument provided is the same as the attribute 248 * name. 249 * 250 * @return if the attribute names correspond. 251 * @param an 252 * An attribute name to be compared with this name. 253 * @since Android 1.0 254 */ 255 @Override equals(Object an)256 public boolean equals(Object an) { 257 if (an == null) { 258 return false; 259 } 260 return an.getClass() == this.getClass() 261 && name.equalsIgnoreCase(((Name) an).name); 262 } 263 264 /** 265 * Computes a hash code of the name. 266 * 267 * @return the hash value computed from the name. 268 * @since Android 1.0 269 */ 270 @Override hashCode()271 public int hashCode() { 272 if (hashCode == 0) { 273 hashCode = Util.toASCIILowerCase("name").hashCode(); 274 } 275 return hashCode; 276 } 277 } 278 279 /** 280 * Constructs an {@code Attributes} instance. 281 * 282 * @since Android 1.0 283 */ Attributes()284 public Attributes() { 285 map = new HashMap<Object, Object>(); 286 } 287 288 /** 289 * Constructs an {@code Attributes} instance obtaining keys and values from 290 * the parameter {@code attrib}. 291 * 292 * @param attrib 293 * The attributes to obtain entries from. 294 * @since Android 1.0 295 */ 296 @SuppressWarnings("unchecked") Attributes(Attributes attrib)297 public Attributes(Attributes attrib) { 298 map = (Map<Object, Object>)((HashMap) attrib.map).clone(); 299 } 300 301 /** 302 * Constructs an {@code Attributes} instance with initial capacity of size 303 * {@code size}. 304 * 305 * @param size 306 * Initial size of this {@code Attributes} instance. 307 * @since Android 1.0 308 */ Attributes(int size)309 public Attributes(int size) { 310 map = new HashMap<Object, Object>(size); 311 } 312 313 /** 314 * Removes all key/value pairs from this {@code Attributes}. 315 * 316 * @since Android 1.0 317 */ clear()318 public void clear() { 319 map.clear(); 320 } 321 322 /** 323 * Determines whether this {@code Attributes} contains the specified key. 324 * 325 * @param key 326 * The key to search for. 327 * @return {@code true} if the key is found, {@code false} otherwise. 328 * @since Android 1.0 329 */ containsKey(Object key)330 public boolean containsKey(Object key) { 331 return map.containsKey(key); 332 } 333 334 /** 335 * Determines whether this {@code Attributes} contains the specified value. 336 * 337 * @param value 338 * the value to search for. 339 * @return {@code true} if the value is found, {@code false} otherwise. 340 * @since Android 1.0 341 */ containsValue(Object value)342 public boolean containsValue(Object value) { 343 return map.containsValue(value); 344 } 345 346 /** 347 * Returns a set containing map entries for each of the key/value pair 348 * contained in this {@code Attributes}. 349 * 350 * @return a set of Map.Entry's 351 * @since Android 1.0 352 */ entrySet()353 public Set<Map.Entry<Object, Object>> entrySet() { 354 return map.entrySet(); 355 } 356 357 /** 358 * Returns the value associated with the parameter key. 359 * 360 * @param key 361 * the key to search for. 362 * @return Object associated with key, or {@code null} if key does not 363 * exist. 364 * @since Android 1.0 365 */ get(Object key)366 public Object get(Object key) { 367 return map.get(key); 368 } 369 370 /** 371 * Determines whether this {@code Attributes} contains any keys. 372 * 373 * @return {@code true} if one or more keys exist, {@code false} otherwise. 374 * @since Android 1.0 375 */ isEmpty()376 public boolean isEmpty() { 377 return map.isEmpty(); 378 } 379 380 /** 381 * Returns a {@code Set} containing all the keys found in this {@code 382 * Attributes}. 383 * 384 * @return a {@code Set} of all keys. 385 * @since Android 1.0 386 */ keySet()387 public Set<Object> keySet() { 388 return map.keySet(); 389 } 390 391 /** 392 * Stores key/value pairs in this {@code Attributes}. 393 * 394 * @param key 395 * the key to associate with value. 396 * @param value 397 * the value to store in this {@code Attributes}. 398 * @return the value being stored. 399 * @exception ClassCastException 400 * when key is not an {@code Attributes.Name} or value is not 401 * a {@code String}. 402 *@since Android 1.0 403 */ 404 @SuppressWarnings("cast") // Require cast to force ClassCastException put(Object key, Object value)405 public Object put(Object key, Object value) { 406 return map.put((Name)key, (String)value); 407 } 408 409 /** 410 * Stores all the key/value pairs in the argument in this {@code Attributes} 411 * . 412 * 413 * @param attrib 414 * the associations to store (must be of type {@code Attributes} 415 * ). 416 * @since Android 1.0 417 */ putAll(Map<?, ?> attrib)418 public void putAll(Map<?, ?> attrib) { 419 if (attrib == null || !(attrib instanceof Attributes)) { 420 throw new ClassCastException(); 421 } 422 this.map.putAll(attrib); 423 } 424 425 /** 426 * Deletes the key/value pair with key {@code key} from this {@code 427 * Attributes}. 428 * 429 * @param key 430 * the key to remove. 431 * @return the values associated with the removed key, {@code null} if not 432 * present. 433 * @since Android 1.0 434 */ remove(Object key)435 public Object remove(Object key) { 436 return map.remove(key); 437 } 438 439 /** 440 * Returns the number of key/value pairs associated with this {@code 441 * Attributes}. 442 * 443 * @return the size of this {@code Attributes}. 444 * @since Android 1.0 445 */ size()446 public int size() { 447 return map.size(); 448 } 449 450 /** 451 * Returns a collection of all the values present in this {@code Attributes} 452 * . 453 * 454 * @return a collection of all values present. 455 * @since Android 1.0 456 */ values()457 public Collection<Object> values() { 458 return map.values(); 459 } 460 461 @SuppressWarnings("unchecked") 462 @Override clone()463 public Object clone() { 464 Attributes clone; 465 try { 466 clone = (Attributes) super.clone(); 467 } catch (CloneNotSupportedException e) { 468 return null; 469 } 470 clone.map = (Map<Object, Object>) ((HashMap) map).clone(); 471 return clone; 472 } 473 474 /** 475 * Returns the hash code of this {@code Attributes}. 476 * 477 * @return the hash code of this object. 478 * @since Android 1.0 479 */ 480 @Override hashCode()481 public int hashCode() { 482 return map.hashCode(); 483 } 484 485 /** 486 * Determines if this {@code Attributes} and the parameter {@code 487 * Attributes} are equal. Two {@code Attributes} instances are equal if they 488 * contain the same keys and values. 489 * 490 * @param obj 491 * the object with which this {@code Attributes} is compared. 492 * @return {@code true} if the {@code Attributes} are equal, {@code false} 493 * otherwise. 494 * @since Android 1.0 495 */ 496 @Override equals(Object obj)497 public boolean equals(Object obj) { 498 if (this == obj) { 499 return true; 500 } 501 if (obj instanceof Attributes) { 502 return map.equals(((Attributes) obj).map); 503 } 504 return false; 505 } 506 507 /** 508 * Returns the value associated with the parameter {@code Attributes.Name} 509 * key. 510 * 511 * @param name 512 * the key to obtain the value for. 513 * @return the {@code String} associated with name, or {@code null} if name 514 * is not a valid key. 515 * @since Android 1.0 516 */ getValue(Attributes.Name name)517 public String getValue(Attributes.Name name) { 518 return (String) map.get(name); 519 } 520 521 /** 522 * Returns the string associated with the parameter name. 523 * 524 * @param name 525 * the key to obtain the value for. 526 * @return the string associated with name, or {@code null} if name is not a 527 * valid key. 528 * @since Android 1.0 529 */ getValue(String name)530 public String getValue(String name) { 531 return (String) map.get(new Attributes.Name(name)); 532 } 533 534 /** 535 * Stores the value {@code val} associated with the key {@code name} in this 536 * {@code Attributes}. 537 * 538 * @param name 539 * the key to store. 540 * @param val 541 * the value to store in this {@code Attributes}. 542 * @return the value being stored. 543 * @since Android 1.0 544 */ putValue(String name, String val)545 public String putValue(String name, String val) { 546 return (String) map.put(new Attributes.Name(name), val); 547 } 548 } 549