• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package java.util.jar;
19 
20 import java.io.UnsupportedEncodingException;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.Set;
25 
26 import org.apache.harmony.archive.util.Util;
27 
28 /**
29  * The {@code Attributes} class is used to store values for manifest entries.
30  * Attribute keys are generally instances of {@code Attributes.Name}. Values
31  * associated with attribute keys are of type {@code String}.
32  */
33 public class Attributes implements Cloneable, Map<Object, Object> {
34 
35     /**
36      * The {@code Attributes} as name/value pairs. Maps the attribute names (as
37      * {@link Attributes.Name}) of a JAR file manifest to arbitrary values. The
38      * attribute names thus are obtained from the {@link Manifest} for
39      * convenience.
40      */
41     protected Map<Object, Object> map;
42 
43     /**
44      * The name part of the name/value pairs constituting an attribute as
45      * defined by the specification of the JAR manifest. May be composed of the
46      * following ASCII signs as defined in the EBNF below:
47      *
48      * <pre>
49      * name       = alphanum *headerchar
50      * headerchar = alphanum | - | _
51      * alphanum   = {A-Z} | {a-z} | {0-9}
52      * </pre>
53      */
54     public static class Name {
55         private final byte[] name;
56 
57         private int hashCode;
58 
59         /**
60          * The class path (a main attribute).
61          */
62         public static final Name CLASS_PATH = new Name("Class-Path"); //$NON-NLS-1$
63 
64         /**
65          * The version of the manifest file (a main attribute).
66          */
67         public static final Name MANIFEST_VERSION = new Name("Manifest-Version"); //$NON-NLS-1$
68 
69         /**
70          * The main class's name (for stand-alone applications).
71          */
72         public static final Name MAIN_CLASS = new Name("Main-Class"); //$NON-NLS-1$
73 
74         /**
75          * Defines the signature version of the JAR file.
76          */
77         public static final Name SIGNATURE_VERSION = new Name(
78                 "Signature-Version"); //$NON-NLS-1$
79 
80         /**
81          * The {@code Content-Type} manifest attribute.
82          */
83         public static final Name CONTENT_TYPE = new Name("Content-Type"); //$NON-NLS-1$
84 
85         /**
86          * The {@code Sealed} manifest attribute which may have the value
87          * {@code true} for sealed archives.
88          */
89         public static final Name SEALED = new Name("Sealed"); //$NON-NLS-1$
90 
91         /**
92          * The {@code Implementation-Title} attribute whose value is a string
93          * that defines the title of the extension implementation.
94          */
95         public static final Name IMPLEMENTATION_TITLE = new Name(
96                 "Implementation-Title"); //$NON-NLS-1$
97 
98         /**
99          * The {@code Implementation-Version} attribute defining the version of
100          * the extension implementation.
101          */
102         public static final Name IMPLEMENTATION_VERSION = new Name(
103                 "Implementation-Version"); //$NON-NLS-1$
104 
105         /**
106          * The {@code Implementation-Vendor} attribute defining the organization
107          * that maintains the extension implementation.
108          */
109         public static final Name IMPLEMENTATION_VENDOR = new Name(
110                 "Implementation-Vendor"); //$NON-NLS-1$
111 
112         /**
113          * The {@code Specification-Title} attribute defining the title of the
114          * extension specification.
115          */
116         public static final Name SPECIFICATION_TITLE = new Name(
117                 "Specification-Title"); //$NON-NLS-1$
118 
119         /**
120          * The {@code Specification-Version} attribute defining the version of
121          * the extension specification.
122          */
123         public static final Name SPECIFICATION_VERSION = new Name(
124                 "Specification-Version"); //$NON-NLS-1$
125 
126         /**
127          * The {@code Specification-Vendor} attribute defining the organization
128          * that maintains the extension specification.
129          */
130         public static final Name SPECIFICATION_VENDOR = new Name(
131                 "Specification-Vendor"); //$NON-NLS-1$
132 
133         /**
134          * The {@code Extension-List} attribute defining the extensions that are
135          * needed by the applet.
136          */
137         public static final Name EXTENSION_LIST = new Name("Extension-List"); //$NON-NLS-1$
138 
139         /**
140          * The {@code Extension-Name} attribute which defines the unique name of
141          * the extension.
142          */
143         public static final Name EXTENSION_NAME = new Name("Extension-Name"); //$NON-NLS-1$
144 
145         /**
146          * The {@code Extension-Installation} attribute.
147          */
148         public static final Name EXTENSION_INSTALLATION = new Name(
149                 "Extension-Installation"); //$NON-NLS-1$
150 
151         /**
152          * The {@code Implementation-Vendor-Id} attribute specifies the vendor
153          * of an extension implementation if the applet requires an
154          * implementation from a specific vendor.
155          */
156         public static final Name IMPLEMENTATION_VENDOR_ID = new Name(
157                 "Implementation-Vendor-Id"); //$NON-NLS-1$
158 
159         /**
160          * The {@code Implementation-URL} attribute specifying a URL that can be
161          * used to obtain the most recent version of the extension if the
162          * required version is not already installed.
163          */
164         public static final Name IMPLEMENTATION_URL = new Name(
165                 "Implementation-URL"); //$NON-NLS-1$
166 
167         static final Name NAME = new Name("Name");
168 
169         /**
170          * A String which must satisfy the following EBNF grammar to specify an
171          * additional attribute:
172          *
173          * <pre>
174          * name       = alphanum *headerchar
175          * headerchar = alphanum | - | _
176          * alphanum   = {A-Z} | {a-z} | {0-9}
177          * </pre>
178          *
179          * @param s
180          *            The Attribute string.
181          * @exception IllegalArgumentException
182          *                if the string does not satisfy the EBNF grammar.
183          */
Name(String s)184         public Name(String s) {
185             int i = s.length();
186             if (i == 0 || i > Manifest.LINE_LENGTH_LIMIT - 2) {
187                 throw new IllegalArgumentException();
188             }
189 
190             name = new byte[i];
191 
192             for (; --i >= 0;) {
193                 char ch = s.charAt(i);
194                 if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
195                         || ch == '_' || ch == '-' || (ch >= '0' && ch <= '9'))) {
196                     throw new IllegalArgumentException(s);
197                 }
198                 name[i] = (byte) ch;
199             }
200         }
201 
202         /**
203          * A private constructor for a trusted attribute name.
204          */
Name(byte[] buf)205         Name(byte[] buf) {
206             name = buf;
207         }
208 
getBytes()209         byte[] getBytes() {
210             return name;
211         }
212 
213         /**
214          * Returns this attribute name.
215          *
216          * @return the attribute name.
217          */
218         @Override
toString()219         public String toString() {
220             try {
221                 return new String(name, "ISO-8859-1");
222             } catch (UnsupportedEncodingException iee) {
223                 throw new InternalError(iee.getLocalizedMessage());
224             }
225         }
226 
227         /**
228          * returns whether the argument provided is the same as the attribute
229          * name.
230          *
231          * @return if the attribute names correspond.
232          * @param object
233          *            An attribute name to be compared with this name.
234          */
235         @Override
equals(Object object)236         public boolean equals(Object object) {
237             if (object == null || object.getClass() != getClass()
238                     || object.hashCode() != hashCode()) {
239                 return false;
240             }
241 
242             return Util.equalsIgnoreCase(name, ((Name) object).name);
243         }
244 
245         /**
246          * Computes a hash code of the name.
247          *
248          * @return the hash value computed from the name.
249          */
250         @Override
hashCode()251         public int hashCode() {
252             if (hashCode == 0) {
253                 int hash = 0, multiplier = 1;
254                 for (int i = name.length - 1; i >= 0; i--) {
255                     // 'A' & 0xDF == 'a' & 0xDF, ..., 'Z' & 0xDF == 'z' & 0xDF
256                     hash += (name[i] & 0xDF) * multiplier;
257                     int shifted = multiplier << 5;
258                     multiplier = shifted - multiplier;
259                 }
260                 hashCode = hash;
261             }
262             return hashCode;
263         }
264 
265     }
266 
267     /**
268      * Constructs an {@code Attributes} instance.
269      */
Attributes()270     public Attributes() {
271         map = new HashMap<Object, Object>();
272     }
273 
274     /**
275      * Constructs an {@code Attributes} instance obtaining keys and values from
276      * the parameter {@code attrib}.
277      *
278      * @param attrib
279      *            The attributes to obtain entries from.
280      */
281     @SuppressWarnings("unchecked")
Attributes(Attributes attrib)282     public Attributes(Attributes attrib) {
283         map = (Map<Object, Object>) ((HashMap) attrib.map).clone();
284     }
285 
286     /**
287      * Constructs an {@code Attributes} instance with initial capacity of size
288      * {@code size}.
289      *
290      * @param size
291      *            Initial size of this {@code Attributes} instance.
292      */
Attributes(int size)293     public Attributes(int size) {
294         map = new HashMap<Object, Object>(size);
295     }
296 
297     /**
298      * Removes all key/value pairs from this {@code Attributes}.
299      */
clear()300     public void clear() {
301         map.clear();
302     }
303 
304     /**
305      * Determines whether this {@code Attributes} contains the specified key.
306      *
307      * @param key
308      *            The key to search for.
309      * @return {@code true} if the key is found, {@code false} otherwise.
310      */
containsKey(Object key)311     public boolean containsKey(Object key) {
312         return map.containsKey(key);
313     }
314 
315     /**
316      * Determines whether this {@code Attributes} contains the specified value.
317      *
318      * @param value
319      *            the value to search for.
320      * @return {@code true} if the value is found, {@code false} otherwise.
321      */
containsValue(Object value)322     public boolean containsValue(Object value) {
323         return map.containsValue(value);
324     }
325 
326     /**
327      * Returns a set containing map entries for each of the key/value pair
328      * contained in this {@code Attributes}.
329      *
330      * @return a set of Map.Entry's
331      */
entrySet()332     public Set<Map.Entry<Object, Object>> entrySet() {
333         return map.entrySet();
334     }
335 
336     /**
337      * Returns the value associated with the parameter key.
338      *
339      * @param key
340      *            the key to search for.
341      * @return Object associated with key, or {@code null} if key does not
342      *         exist.
343      */
get(Object key)344     public Object get(Object key) {
345         return map.get(key);
346     }
347 
348     /**
349      * Determines whether this {@code Attributes} contains any keys.
350      *
351      * @return {@code true} if one or more keys exist, {@code false} otherwise.
352      */
isEmpty()353     public boolean isEmpty() {
354         return map.isEmpty();
355     }
356 
357     /**
358      * Returns a {@code Set} containing all the keys found in this {@code
359      * Attributes}.
360      *
361      * @return a {@code Set} of all keys.
362      */
keySet()363     public Set<Object> keySet() {
364         return map.keySet();
365     }
366 
367     /**
368      * Stores key/value pairs in this {@code Attributes}.
369      *
370      * @param key
371      *            the key to associate with value.
372      * @param value
373      *            the value to store in this {@code Attributes}.
374      * @return the value being stored.
375      * @exception ClassCastException
376      *                when key is not an {@code Attributes.Name} or value is not
377      *                a {@code String}.
378      */
379     @SuppressWarnings("cast")
380     // Require cast to force ClassCastException
put(Object key, Object value)381     public Object put(Object key, Object value) {
382         return map.put((Name) key, (String) value);
383     }
384 
385     /**
386      * Stores all the key/value pairs in the argument in this {@code
387      * Attributes}.
388      *
389      * @param attrib
390      *            the associations to store (must be of type {@code
391      *            Attributes}).
392      */
putAll(Map<?, ?> attrib)393     public void putAll(Map<?, ?> attrib) {
394         if (attrib == null || !(attrib instanceof Attributes)) {
395             throw new ClassCastException();
396         }
397         this.map.putAll(attrib);
398     }
399 
400     /**
401      * Deletes the key/value pair with key {@code key} from this {@code
402      * Attributes}.
403      *
404      * @param key
405      *            the key to remove.
406      * @return the values associated with the removed key, {@code null} if not
407      *         present.
408      */
remove(Object key)409     public Object remove(Object key) {
410         return map.remove(key);
411     }
412 
413     /**
414      * Returns the number of key/value pairs associated with this {@code
415      * Attributes}.
416      *
417      * @return the size of this {@code Attributes}.
418      */
size()419     public int size() {
420         return map.size();
421     }
422 
423     /**
424      * Returns a collection of all the values present in this {@code
425      * Attributes}.
426      *
427      * @return a collection of all values present.
428      */
values()429     public Collection<Object> values() {
430         return map.values();
431     }
432 
433     @SuppressWarnings("unchecked")
434     @Override
clone()435     public Object clone() {
436         Attributes clone;
437         try {
438             clone = (Attributes) super.clone();
439         } catch (CloneNotSupportedException e) {
440             return null;
441         }
442         clone.map = (Map<Object, Object>) ((HashMap) map).clone();
443         return clone;
444     }
445 
446     /**
447      * Returns the hash code of this {@code Attributes}.
448      *
449      * @return the hash code of this object.
450      */
451     @Override
hashCode()452     public int hashCode() {
453         return map.hashCode();
454     }
455 
456     /**
457      * Determines if this {@code Attributes} and the parameter {@code
458      * Attributes} are equal. Two {@code Attributes} instances are equal if they
459      * contain the same keys and values.
460      *
461      * @param obj
462      *            the object with which this {@code Attributes} is compared.
463      * @return {@code true} if the {@code Attributes} are equal, {@code false}
464      *         otherwise.
465      */
466     @Override
equals(Object obj)467     public boolean equals(Object obj) {
468         if (this == obj) {
469             return true;
470         }
471         if (obj instanceof Attributes) {
472             return map.equals(((Attributes) obj).map);
473         }
474         return false;
475     }
476 
477     /**
478      * Returns the value associated with the parameter {@code Attributes.Name}
479      * key.
480      *
481      * @param name
482      *            the key to obtain the value for.
483      * @return the {@code String} associated with name, or {@code null} if name
484      *         is not a valid key.
485      */
getValue(Attributes.Name name)486     public String getValue(Attributes.Name name) {
487         return (String) map.get(name);
488     }
489 
490     /**
491      * Returns the string associated with the parameter name.
492      *
493      * @param name
494      *            the key to obtain the value for.
495      * @return the string associated with name, or {@code null} if name is not a
496      *         valid key.
497      */
getValue(String name)498     public String getValue(String name) {
499         return (String) map.get(new Attributes.Name(name));
500     }
501 
502     /**
503      * Stores the value {@code val} associated with the key {@code name} in this
504      * {@code Attributes}.
505      *
506      * @param name
507      *            the key to store.
508      * @param val
509      *            the value to store in this {@code Attributes}.
510      * @return the value being stored.
511      */
putValue(String name, String val)512     public String putValue(String name, String val) {
513         return (String) map.put(new Attributes.Name(name), val);
514     }
515 }
516