Source for java.util.jar.Attributes

   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> &lt;extension&gt;-Extension-Name:
 155:      * unique name of the extension</li>
 156:      * <li> &lt;extension&gt;-Specification-Version:
 157:      * minimum specification version</li>
 158:      * <li> &lt;extension&gt;-Implementation-Version:
 159:      * minimum implementation version</li>
 160:      * <li> &lt;extension&gt;-Implementation-Vendor-Id:
 161:      * unique id of implementation vendor</li>
 162:      * <li> &lt;extension&gt;-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: }