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