GNU Classpath (0.95) | |
Frames | No Frames |
1: /* Attributes.java -- Represents attribute name/value pairs from a Manifest 2: Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package java.util.jar; 39: 40: import gnu.java.util.jar.JarUtils; 41: 42: import java.util.Collection; 43: import java.util.Hashtable; 44: import java.util.Map; 45: import java.util.Set; 46: 47: /** 48: * Represents attribute name/value pairs from a Manifest as a Map. 49: * The names of an attribute are represented by the 50: * <code>Attributes.Name</code> class and should confirm to the restrictions 51: * described in that class. Note that the Map interface that Attributes 52: * implements allows you to put names and values into the attribute that don't 53: * follow these restriction (and are not really Atrribute.Names, but if you do 54: * that it might cause undefined behaviour later). 55: * <p> 56: * If you use the constants defined in the inner class Name then you can be 57: * sure that you always access the right attribute names. This makes 58: * manipulating the Attributes more or less type safe. 59: * <p> 60: * Most of the methods are wrappers to implement the Map interface. The really 61: * useful and often used methods are <code>getValue(Name)</code> and 62: * <code>getValue(String)</code>. If you actually want to set attributes you 63: * may want to use the <code>putValue(String, String)</code> method 64: * (sorry there is no public type safe <code>putValue(Name, String)</code> 65: * method). 66: * 67: * @see java.util.jar.Attributes.Name 68: * @author Mark Wielaard (mark@klomp.org) 69: */ 70: public class Attributes 71: implements Cloneable, Map<Object, Object> 72: { 73: 74: // Fields 75: 76: /** 77: * The map that holds all the attribute name/value pairs. In this 78: * implementation it is actually a Hashtable, but that can be different in 79: * other implementations. 80: */ 81: protected Map<Object, Object> map; 82: 83: // Inner class 84: 85: /** 86: * Represents a name of a Manifest Attribute. Defines a couple of well 87: * know names for the general main attributes, stand alone application 88: * attributes, applet attributes, extension identification attributes, 89: * package versioning and sealing attributes, file contents attributes, 90: * bean objects attribute and signing attributes. See the 91: * 92: * <p>The characters of a Name must obey the following restrictions:</p> 93: * 94: * <ul> 95: * <li>Must contain at least one character</li> 96: * <li>The first character must be alphanumeric (a-z, A-Z, 0-9)</li> 97: * <li>All other characters must be alphanumeric, a '-' or a '_'</li> 98: * </ul> 99: * 100: * <p>When comparing Names (with <code>equals</code>) all characters are 101: * converted to lowercase. But you can get the original case sensitive 102: * string with the <code>toString()</code> method.</p> 103: * 104: * <p>Most important attributes have a constant defined in this 105: * class. Some other attributes used in Manifest files are: 106: * <ul> 107: * <li> "Created-By" - General main attribute, tool and version 108: * that created this Manifest file.</li> 109: * <li> "Java-Bean" - Bean objects attribute, whether the entry is a Bean. 110: * Value is either "true" or "false".</li> 111: * <li> "Magic" - Signing attribute, application specific signing attribute. 112: * Must be understood by the manifest parser when present to validate the 113: * jar (entry).</li> 114: * </ul> 115: * 116: * @since 1.2 117: * @author Mark Wielaard (mark@klomp.org) 118: */ 119: public static class Name 120: { 121: // General Main Attributes 122: 123: /** 124: * General main attribute - 125: * the version of this Manifest file. 126: */ 127: public static final Name MANIFEST_VERSION = new Name(JarUtils.MANIFEST_VERSION); 128: 129: /** 130: * General main attribute - 131: * the version of the jar file signature. 132: */ 133: public static final Name SIGNATURE_VERSION = new Name(JarUtils.SIGNATURE_VERSION); 134: 135: /** 136: * General main attribute - 137: * (relative) file paths of the libraries/classpaths that the Classes in 138: * this jar file depend on. Paths are separated by spaces. 139: */ 140: public static final Name CLASS_PATH = new Name("Class-Path"); 141: 142: /** 143: * Stand alone application attribute - 144: * the entry (without the .class ending) that is the main 145: * class of this jar file. 146: */ 147: public static final Name MAIN_CLASS = new Name("Main-Class"); 148: 149: /** 150: * Applet attribute - 151: * a list of extension libraries that the applet in this 152: * jar file depends on. 153: * For every named extension there should be some Attributes in the 154: * Manifest manifest file with the following Names: 155: * <ul> 156: * <li> <extension>-Extension-Name: 157: * unique name of the extension</li> 158: * <li> <extension>-Specification-Version: 159: * minimum specification version</li> 160: * <li> <extension>-Implementation-Version: 161: * minimum implementation version</li> 162: * <li> <extension>-Implementation-Vendor-Id: 163: * unique id of implementation vendor</li> 164: * <li> <extension>-Implementation-URL: 165: * where the latest version of the extension library can be found</li> 166: * </ul> 167: */ 168: public static final Name EXTENSION_LIST = new Name("Extension-List"); 169: 170: /** 171: * Extension identification attribute - 172: * the name if the extension library contained in the jar. 173: */ 174: public static final Name EXTENSION_NAME = new Name("Extension-Name"); 175: 176: /** 177: * Extension identification attribute - 178: * synonym for <code>EXTENSTION_NAME</code>. 179: */ 180: public static final Name EXTENSION_INSTALLATION = EXTENSION_NAME; 181: 182: // Package versioning and sealing attributes 183: 184: /** 185: * Package versioning - 186: * name of extension library contained in this jar. 187: */ 188: public static final Name IMPLEMENTATION_TITLE 189: = new Name("Implementation-Title"); 190: 191: /** 192: * Package versioning - 193: * version of the extension library contained in this jar. 194: */ 195: public static final Name IMPLEMENTATION_VERSION 196: = new Name("Implementation-Version"); 197: 198: /** 199: * Package versioning - 200: * name of extension library creator contained in this jar. 201: */ 202: public static final Name IMPLEMENTATION_VENDOR 203: = new Name("Implementation-Vendor"); 204: 205: /** 206: * Package versioning - 207: * unique id of extension library creator. 208: */ 209: public static final Name IMPLEMENTATION_VENDOR_ID 210: = new Name("Implementation-Vendor-Id"); 211: 212: /** 213: * Package versioning - 214: * location where this implementation can be downloaded. 215: */ 216: public static final Name IMPLEMENTATION_URL 217: = new Name("Implementation-URL"); 218: 219: /** 220: * Package versioning - 221: * title of the specification contained in this jar. 222: */ 223: public static final Name SPECIFICATION_TITLE 224: = new Name("Specification-Title"); 225: 226: /** 227: * Package versioning - 228: * version of the specification contained in this jar. 229: */ 230: public static final Name SPECIFICATION_VERSION 231: = new Name("Specification-Version"); 232: 233: /** 234: * Package versioning - 235: * organisation that maintains the specification contains in this 236: * jar. 237: */ 238: public static final Name SPECIFICATION_VENDOR 239: = new Name("Specification-Vendor"); 240: 241: /** 242: * Package sealing - 243: * whether (all) package(s) is(/are) sealed. Value is either "true" 244: * or "false". 245: */ 246: public static final Name SEALED = new Name("Sealed"); 247: 248: /** 249: * File contents attribute - 250: * Mime type and subtype for the jar entry. 251: */ 252: public static final Name CONTENT_TYPE = new Name("Content-Type"); 253: 254: /** The (lowercase) String representation of this Name */ 255: private final String name; 256: 257: /** The original String given to the constructor */ 258: private final String origName; 259: 260: // Constructor 261: 262: /** 263: * Creates a new Name from the given String. 264: * Throws an IllegalArgumentException if the given String is empty or 265: * contains any illegal Name characters. 266: * 267: * @param name the name of the new Name 268: * @exception IllegalArgumentException if name isn't a valid String 269: * representation of a Name 270: * @exception NullPointerException if name is null 271: */ 272: public Name(String name) throws IllegalArgumentException, 273: NullPointerException 274: { 275: // name must not be null 276: // this will throw a NullPointerException if it is 277: char chars[] = name.toCharArray(); 278: 279: // there must be at least one character 280: if (chars.length == 0) 281: throw new 282: IllegalArgumentException 283: ("There must be at least one character in a name"); 284: 285: // first character must be alphanum 286: char c = chars[0]; 287: if (!((c >= 'a' && c <= 'z') || 288: (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))) 289: throw new 290: IllegalArgumentException("First character must be alphanum"); 291: 292: // all other characters must be alphanums, '-' or '_' 293: for (int i = 1; i < chars.length; i++) 294: { 295: c = chars[i]; 296: if (!((c >= 'a' && c <= 'z') || 297: (c >= 'A' && c <= 'Z') || 298: (c >= '0' && c <= '9') || (c == '-') || (c == '_'))) 299: throw new 300: IllegalArgumentException 301: ("Characters must be alphanums, '-' or '_'"); 302: } 303: 304: // Still here? Then convert to lower case and be done. 305: // Store the original name for toString(); 306: this.origName = name; 307: this.name = name.toLowerCase(); 308: } 309: 310: /** 311: * Returns the hash code of the (lowercase) String representation of 312: * this Name. 313: */ 314: public int hashCode() 315: { 316: return name.hashCode(); 317: } 318: 319: /** 320: * Checks if another object is equal to this Name object. 321: * Another object is equal to this Name object if it is an instance of 322: * Name and the (lowercase) string representation of the name is equal. 323: */ 324: public boolean equals(Object o) 325: { 326: // Quick and dirty check 327: if (name == o) 328: return true; 329: 330: try 331: { 332: // Note that the constructor already converts the strings to 333: // lowercase. 334: String otherName = ((Name) o).name; 335: return name.equals(otherName); 336: } 337: catch (ClassCastException cce) 338: { 339: return false; 340: } 341: catch (NullPointerException npe) 342: { 343: return false; 344: } 345: } 346: 347: /** 348: * Returns the string representation of this Name as given to the 349: * constructor (not neccesarily the lower case representation). 350: */ 351: public String toString() 352: { 353: return origName; 354: } 355: } 356: 357: // Constructors 358: 359: /** 360: * Creates an empty Attributes map. 361: */ 362: public Attributes() 363: { 364: map = new Hashtable(); 365: } 366: 367: /** 368: * Creates an empty Attributes map with the given initial size. 369: * @param size the initial size of the underlying map 370: */ 371: public Attributes(int size) 372: { 373: map = new Hashtable(size); 374: } 375: 376: /** 377: * Creates an Attributes map with the initial values taken from another 378: * Attributes map. 379: * @param attr Attributes map to take the initial values from 380: */ 381: public Attributes(Attributes attr) 382: { 383: map = new Hashtable(attr.map); 384: } 385: 386: // Methods 387: 388: /** 389: * Gets the value of an attribute name given as a String. 390: * 391: * @param name a String describing the Name to look for 392: * @return the value gotten from the map of null when not found 393: */ 394: public String getValue(String name) 395: { 396: return (String) get(new Name(name)); 397: } 398: 399: /** 400: * Gets the value of the given attribute name. 401: * 402: * @param name the Name to look for 403: * @return the value gotten from the map of null when not found 404: */ 405: public String getValue(Name name) 406: { 407: return (String) get(name); 408: } 409: 410: /** 411: * Stores an attribute name (represented by a String) and value in this 412: * Attributes map. 413: * When the (case insensitive string) name already exists the value is 414: * replaced and the old value is returned. 415: * 416: * @param name a (case insensitive) String representation of the attribite 417: * name to add/replace 418: * @param value the (new) value of the attribute name 419: * @returns the old value of the attribute name or null if it didn't exist 420: * yet 421: */ 422: public String putValue(String name, String value) 423: { 424: return putValue(new Name(name), value); 425: } 426: 427: /** 428: * Stores an attribute name (represented by a String) and value in this 429: * Attributes map. 430: * When the name already exists the value is replaced and the old value 431: * is returned. 432: * 433: * @param name the attribite name to add/replace 434: * @param value the (new) value of the attribute name 435: * @returns the old value of the attribute name or null if it didn't exist 436: * yet 437: */ 438: private String putValue(Name name, String value) 439: { 440: return (String) put(name, value); 441: } 442: 443: // Methods from Cloneable interface 444: 445: /** 446: * Return a clone of this attribute map. 447: */ 448: public Object clone() 449: { 450: return new Attributes(this); 451: } 452: 453: // Methods from Map interface 454: 455: /** 456: * Removes all attributes. 457: */ 458: public void clear() 459: { 460: map.clear(); 461: } 462: 463: /** 464: * Checks to see if there is an attribute with the specified name. 465: * XXX - what if the object is a String? 466: * 467: * @param attrName the name of the attribute to check 468: * @return true if there is an attribute with the specified name, false 469: * otherwise 470: */ 471: public boolean containsKey(Object attrName) 472: { 473: return map.containsKey(attrName); 474: } 475: 476: /** 477: * Checks to see if there is an attribute name with the specified value. 478: * 479: * @param attrValue the value of a attribute to check 480: * @return true if there is an attribute name with the specified value, 481: * false otherwise 482: */ 483: public boolean containsValue(Object attrValue) 484: { 485: return map.containsValue(attrValue); 486: } 487: 488: /** 489: * Gives a Set of attribute name and values pairs as MapEntries. 490: * @see java.util.Map.Entry 491: * @see java.util.Map#entrySet() 492: * 493: * @return a set of attribute name value pairs 494: */ 495: public Set<Map.Entry<Object, Object>> entrySet() 496: { 497: return map.entrySet(); 498: } 499: 500: /** 501: * Checks to see if two Attributes are equal. The supplied object must be 502: * a real instance of Attributes and contain the same attribute name/value 503: * pairs. 504: * 505: * @param o another Attribute object which should be checked for equality 506: * @return true if the object is an instance of Attributes and contains the 507: * same name/value pairs, false otherwise 508: */ 509: public boolean equals(Object o) 510: { 511: // quick and dirty check 512: if (this == o) 513: return true; 514: 515: try 516: { 517: return map.equals(((Attributes) o).map); 518: } 519: catch (ClassCastException cce) 520: { 521: return false; 522: } 523: catch (NullPointerException npe) 524: { 525: return false; 526: } 527: } 528: 529: /** 530: * Gets the value of a specified attribute name. 531: * XXX - what if the object is a String? 532: * 533: * @param attrName the name of the attribute we want the value of 534: * @return the value of the specified attribute name or null when there is 535: * no such attribute name 536: */ 537: public Object get(Object attrName) 538: { 539: return map.get(attrName); 540: } 541: 542: /** 543: * Returns the hashcode of the attribute name/value map. 544: */ 545: public int hashCode() 546: { 547: return map.hashCode(); 548: } 549: 550: /** 551: * Returns true if there are no attributes set, false otherwise. 552: */ 553: public boolean isEmpty() 554: { 555: return map.isEmpty(); 556: } 557: 558: /** 559: * Gives a Set of all the values of defined attribute names. 560: */ 561: public Set<Object> keySet() 562: { 563: return map.keySet(); 564: } 565: 566: /** 567: * Adds or replaces a attribute name/value pair. 568: * XXX - What if the name is a string? What if the name is neither a Name 569: * nor a String? What if the value is not a string? 570: * 571: * @param name the name of the attribute 572: * @param value the (new) value of the attribute 573: * @return the old value of the attribute or null when there was no old 574: * attribute with this name 575: */ 576: public Object put(Object name, Object value) 577: { 578: return map.put(name, value); 579: } 580: 581: /** 582: * Adds or replaces all attribute name/value pairs from another 583: * Attributes object to this one. The supplied Map must be an instance of 584: * Attributes. 585: * 586: * @param attr the Attributes object to merge with this one 587: * @exception ClassCastException if the supplied map is not an instance of 588: * Attributes 589: */ 590: public void putAll(Map<?, ?> attr) 591: { 592: if (!(attr instanceof Attributes)) 593: { 594: throw new 595: ClassCastException("Supplied Map is not an instance of Attributes"); 596: } 597: map.putAll(attr); 598: } 599: 600: /** 601: * Remove a attribute name/value pair. 602: * XXX - What if the name is a String? 603: * 604: * @param name the name of the attribute name/value pair to remove 605: * @return the old value of the attribute or null if the attribute didn't 606: * exist 607: */ 608: public Object remove(Object name) 609: { 610: return map.remove(name); 611: } 612: 613: /** 614: * Returns the number of defined attribute name/value pairs. 615: */ 616: public int size() 617: { 618: return map.size(); 619: } 620: 621: /** 622: * Returns all the values of the defined attribute name/value pairs as a 623: * Collection. 624: */ 625: public Collection<Object> values() 626: { 627: return map.values(); 628: } 629: }
GNU Classpath (0.95) |