1 /* Attributes.java -- Represents attribute name/value pairs from a Manifest
2 Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
38 package java.util.jar;
40 import gnu.java.util.jar.JarUtils;
42 import java.util.Collection;
43 import java.util.Hashtable;
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).
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.
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>
67 * @see java.util.jar.Attributes.Name
68 * @author Mark Wielaard (mark@klomp.org)
70 public class Attributes
71 implements Cloneable, Map<Object, Object>
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.
81 protected Map<Object, Object> map;
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
92 * <p>The characters of a Name must obey the following restrictions:</p>
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>
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>
104 * <p>Most important attributes have a constant defined in this
105 * class. Some other attributes used in Manifest files are:
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
117 * @author Mark Wielaard (mark@klomp.org)
119 public static class Name
121 // General Main Attributes
124 * General main attribute -
125 * the version of this Manifest file.
127 public static final Name MANIFEST_VERSION = new Name(JarUtils.MANIFEST_VERSION);
130 * General main attribute -
131 * the version of the jar file signature.
133 public static final Name SIGNATURE_VERSION = new Name(JarUtils.SIGNATURE_VERSION);
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.
140 public static final Name CLASS_PATH = new Name("Class-Path");
143 * Stand alone application attribute -
144 * the entry (without the .class ending) that is the main
145 * class of this jar file.
147 public static final Name MAIN_CLASS = new Name("Main-Class");
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:
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>
168 public static final Name EXTENSION_LIST = new Name("Extension-List");
171 * Extension identification attribute -
172 * the name if the extension library contained in the jar.
174 public static final Name EXTENSION_NAME = new Name("Extension-Name");
177 * Extension identification attribute -
178 * synonym for <code>EXTENSTION_NAME</code>.
180 public static final Name EXTENSION_INSTALLATION = EXTENSION_NAME;
182 // Package versioning and sealing attributes
185 * Package versioning -
186 * name of extension library contained in this jar.
188 public static final Name IMPLEMENTATION_TITLE
189 = new Name("Implementation-Title");
192 * Package versioning -
193 * version of the extension library contained in this jar.
195 public static final Name IMPLEMENTATION_VERSION
196 = new Name("Implementation-Version");
199 * Package versioning -
200 * name of extension library creator contained in this jar.
202 public static final Name IMPLEMENTATION_VENDOR
203 = new Name("Implementation-Vendor");
206 * Package versioning -
207 * unique id of extension library creator.
209 public static final Name IMPLEMENTATION_VENDOR_ID
210 = new Name("Implementation-Vendor-Id");
213 * Package versioning -
214 * location where this implementation can be downloaded.
216 public static final Name IMPLEMENTATION_URL
217 = new Name("Implementation-URL");
220 * Package versioning -
221 * title of the specification contained in this jar.
223 public static final Name SPECIFICATION_TITLE
224 = new Name("Specification-Title");
227 * Package versioning -
228 * version of the specification contained in this jar.
230 public static final Name SPECIFICATION_VERSION
231 = new Name("Specification-Version");
234 * Package versioning -
235 * organisation that maintains the specification contains in this
238 public static final Name SPECIFICATION_VENDOR
239 = new Name("Specification-Vendor");
243 * whether (all) package(s) is(/are) sealed. Value is either "true"
246 public static final Name SEALED = new Name("Sealed");
249 * File contents attribute -
250 * Mime type and subtype for the jar entry.
252 public static final Name CONTENT_TYPE = new Name("Content-Type");
254 /** The (lowercase) String representation of this Name */
255 private final String name;
257 /** The original String given to the constructor */
258 private final String origName;
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.
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
272 public Name(String name) throws IllegalArgumentException,
275 // name must not be null
276 // this will throw a NullPointerException if it is
277 char chars[] = name.toCharArray();
279 // there must be at least one character
280 if (chars.length == 0)
282 IllegalArgumentException
283 ("There must be at least one character in a name");
285 // first character must be alphanum
287 if (!((c >= 'a' && c <= 'z') ||
288 (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')))
290 IllegalArgumentException("First character must be alphanum");
292 // all other characters must be alphanums, '-' or '_'
293 for (int i = 1; i < chars.length; i++)
296 if (!((c >= 'a' && c <= 'z') ||
297 (c >= 'A' && c <= 'Z') ||
298 (c >= '0' && c <= '9') || (c == '-') || (c == '_')))
300 IllegalArgumentException
301 ("Characters must be alphanums, '-' or '_'");
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();
311 * Returns the hash code of the (lowercase) String representation of
314 public int hashCode()
316 return name.hashCode();
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.
324 public boolean equals(Object o)
326 // Quick and dirty check
332 // Note that the constructor already converts the strings to
334 String otherName = ((Name) o).name;
335 return name.equals(otherName);
337 catch (ClassCastException cce)
341 catch (NullPointerException npe)
348 * Returns the string representation of this Name as given to the
349 * constructor (not neccesarily the lower case representation).
351 public String toString()
360 * Creates an empty Attributes map.
364 map = new Hashtable();
368 * Creates an empty Attributes map with the given initial size.
369 * @param size the initial size of the underlying map
371 public Attributes(int size)
373 map = new Hashtable(size);
377 * Creates an Attributes map with the initial values taken from another
379 * @param attr Attributes map to take the initial values from
381 public Attributes(Attributes attr)
383 map = new Hashtable(attr.map);
389 * Gets the value of an attribute name given as a String.
391 * @param name a String describing the Name to look for
392 * @return the value gotten from the map of null when not found
394 public String getValue(String name)
396 return (String) get(new Name(name));
400 * Gets the value of the given attribute name.
402 * @param name the Name to look for
403 * @return the value gotten from the map of null when not found
405 public String getValue(Name name)
407 return (String) get(name);
411 * Stores an attribute name (represented by a String) and value in this
413 * When the (case insensitive string) name already exists the value is
414 * replaced and the old value is returned.
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
422 public String putValue(String name, String value)
424 return putValue(new Name(name), value);
428 * Stores an attribute name (represented by a String) and value in this
430 * When the name already exists the value is replaced and the old value
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
438 private String putValue(Name name, String value)
440 return (String) put(name, value);
443 // Methods from Cloneable interface
446 * Return a clone of this attribute map.
448 public Object clone()
450 return new Attributes(this);
453 // Methods from Map interface
456 * Removes all attributes.
464 * Checks to see if there is an attribute with the specified name.
465 * XXX - what if the object is a String?
467 * @param attrName the name of the attribute to check
468 * @return true if there is an attribute with the specified name, false
471 public boolean containsKey(Object attrName)
473 return map.containsKey(attrName);
477 * Checks to see if there is an attribute name with the specified value.
479 * @param attrValue the value of a attribute to check
480 * @return true if there is an attribute name with the specified value,
483 public boolean containsValue(Object attrValue)
485 return map.containsValue(attrValue);
489 * Gives a Set of attribute name and values pairs as MapEntries.
490 * @see java.util.Map.Entry
491 * @see java.util.Map#entrySet()
493 * @return a set of attribute name value pairs
495 public Set<Map.Entry<Object, Object>> entrySet()
497 return map.entrySet();
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
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
509 public boolean equals(Object o)
511 // quick and dirty check
517 return map.equals(((Attributes) o).map);
519 catch (ClassCastException cce)
523 catch (NullPointerException npe)
530 * Gets the value of a specified attribute name.
531 * XXX - what if the object is a String?
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
537 public Object get(Object attrName)
539 return map.get(attrName);
543 * Returns the hashcode of the attribute name/value map.
545 public int hashCode()
547 return map.hashCode();
551 * Returns true if there are no attributes set, false otherwise.
553 public boolean isEmpty()
555 return map.isEmpty();
559 * Gives a Set of all the values of defined attribute names.
561 public Set<Object> keySet()
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?
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
576 public Object put(Object name, Object value)
578 return map.put(name, value);
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
586 * @param attr the Attributes object to merge with this one
587 * @exception ClassCastException if the supplied map is not an instance of
590 public void putAll(Map<?, ?> attr)
592 if (!(attr instanceof Attributes))
595 ClassCastException("Supplied Map is not an instance of Attributes");
601 * Remove a attribute name/value pair.
602 * XXX - What if the name is a String?
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
608 public Object remove(Object name)
610 return map.remove(name);
614 * Returns the number of defined attribute name/value pairs.
622 * Returns all the values of the defined attribute name/value pairs as a
625 public Collection<Object> values()