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