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