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