1/*
2 * Conditions Of Use
3 *
4 * This software was developed by employees of the National Institute of
5 * Standards and Technology (NIST), an agency of the Federal Government.
6 * Pursuant to title 15 Untied States Code Section 105, works of NIST
7 * employees are not subject to copyright protection in the United States
8 * and are considered to be in the public domain.  As a result, a formal
9 * license is not needed to use the software.
10 *
11 * This software is provided by NIST as a service and is expressly
12 * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15 * AND DATA ACCURACY.  NIST does not warrant or make any representations
16 * regarding the use of the software or the results thereof, including but
17 * not limited to the correctness, accuracy, reliability or usefulness of
18 * the software.
19 *
20 * Permission to use this software is contingent upon your acceptance
21 * of the terms of this agreement
22 *
23 * .
24 *
25 */
26/*******************************************************************************
27 * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *
28 *******************************************************************************/
29package gov.nist.core;
30
31import java.util.concurrent.*;
32
33import java.io.Serializable;
34import java.util.Collection;
35import java.util.HashMap;
36import java.util.Iterator;
37import java.util.LinkedHashMap;
38import java.util.Map;
39import java.util.Set;
40
41/**
42 * Implements a simple NameValue association with a quick lookup function (via a
43 * hash map) the default behavior for this class is not thread safe.
44 * specify a constructor with boolean true to make this thread safe.
45 *
46 * @version 1.2
47 *
48 * @author M. Ranganathan <br/>
49 *
50 *
51 *
52 */
53
54public class NameValueList implements Serializable, Cloneable, Map<String,NameValue> {
55
56
57    private static final long serialVersionUID = -6998271876574260243L;
58
59    private Map<String,NameValue> hmap;
60
61    private String separator;
62
63    /**
64     * default constructor.
65     */
66    public NameValueList() {
67        this.separator = ";";
68        this.hmap = new LinkedHashMap<String,NameValue>();
69    }
70
71    public NameValueList(boolean sync) {
72        this.separator = ";";
73        if (sync)
74            this.hmap = new ConcurrentHashMap<String,NameValue>();
75        else
76            this.hmap = new LinkedHashMap<String,NameValue>();
77    }
78
79    public void setSeparator(String separator) {
80        this.separator = separator;
81    }
82
83    /**
84     * Encode the list in semicolon separated form.
85     *
86     * @return an encoded string containing the objects in this list.
87     * @since v1.0
88     */
89    public String encode() {
90        return encode(new StringBuffer()).toString();
91    }
92
93    public StringBuffer encode(StringBuffer buffer) {
94        if (!hmap.isEmpty()) {
95            Iterator<NameValue> iterator = hmap.values().iterator();
96            if (iterator.hasNext()) {
97                while (true) {
98                    Object obj = iterator.next();
99                    if (obj instanceof GenericObject) {
100                        GenericObject gobj = (GenericObject) obj;
101                        gobj.encode(buffer);
102                    } else {
103                        buffer.append(obj.toString());
104                    }
105                    if (iterator.hasNext())
106                        buffer.append(separator);
107                    else
108                        break;
109                }
110            }
111        }
112        return buffer;
113    }
114
115    public String toString() {
116        return this.encode();
117    }
118
119    /**
120     * Set a namevalue object in this list.
121     */
122
123    public void set(NameValue nv) {
124        this.hmap.put(nv.getName().toLowerCase(), nv);
125    }
126
127    /**
128     * Set a namevalue object in this list.
129     */
130    public void set(String name, Object value) {
131        NameValue nameValue = new NameValue(name, value);
132        hmap.put(name.toLowerCase(), nameValue);
133
134    }
135
136    /**
137     * Compare if two NameValue lists are equal.
138     *
139     * @param otherObject
140     *            is the object to compare to.
141     * @return true if the two objects compare for equality.
142     */
143    public boolean equals(Object otherObject) {
144        if ( otherObject == null ) {
145            return false;
146        }
147        if (!otherObject.getClass().equals(this.getClass())) {
148            return false;
149        }
150        NameValueList other = (NameValueList) otherObject;
151
152        if (hmap.size() != other.hmap.size()) {
153            return false;
154        }
155        Iterator<String> li = this.hmap.keySet().iterator();
156
157        while (li.hasNext()) {
158            String key = (String) li.next();
159            NameValue nv1 = this.getNameValue(key);
160            NameValue nv2 = (NameValue) other.hmap.get(key);
161            if (nv2 == null)
162                return false;
163            else if (!nv2.equals(nv1))
164                return false;
165        }
166        return true;
167    }
168
169    /**
170     * Do a lookup on a given name and return value associated with it.
171     */
172    public Object getValue(String name) {
173        NameValue nv = this.getNameValue(name.toLowerCase());
174        if (nv != null)
175            return nv.getValueAsObject();
176        else
177            return null;
178    }
179
180    /**
181     * Get the NameValue record given a name.
182     *
183     * @since 1.0
184     */
185    public NameValue getNameValue(String name) {
186        return (NameValue) this.hmap.get(name.toLowerCase());
187    }
188
189    /**
190     * Returns a boolean telling if this NameValueList has a record with this
191     * name
192     *
193     * @since 1.0
194     */
195    public boolean hasNameValue(String name) {
196        return hmap.containsKey(name.toLowerCase());
197    }
198
199    /**
200     * Remove the element corresponding to this name.
201     *
202     * @since 1.0
203     */
204    public boolean delete(String name) {
205        String lcName = name.toLowerCase();
206        if (this.hmap.containsKey(lcName)) {
207            this.hmap.remove(lcName);
208            return true;
209        } else {
210            return false;
211        }
212
213    }
214
215    public Object clone() {
216        NameValueList retval = new NameValueList();
217        retval.setSeparator(this.separator);
218        Iterator<NameValue> it = this.hmap.values().iterator();
219        while (it.hasNext()) {
220            retval.set((NameValue) ((NameValue) it.next()).clone());
221        }
222        return retval;
223    }
224
225    /**
226     * Return the size of the embedded map
227     */
228    public int size() {
229        return this.hmap.size();
230    }
231
232    /**
233     * Return true if empty.
234     */
235    public boolean isEmpty() {
236        return hmap.isEmpty();
237    }
238
239    /**
240     * Return an iterator for the name-value pairs of this list.
241     *
242     * @return the iterator.
243     */
244    public Iterator<NameValue> iterator() {
245        return this.hmap.values().iterator();
246    }
247
248    /**
249     * Get a list of parameter names.
250     *
251     * @return a list iterator that has the names of the parameters.
252     */
253    public Iterator<String> getNames() {
254        return this.hmap.keySet().iterator();
255
256    }
257
258    /**
259     * Get the parameter as a String.
260     *
261     * @return the parameter as a string.
262     */
263    public String getParameter(String name) {
264        Object val = this.getValue(name);
265        if (val == null)
266            return null;
267        if (val instanceof GenericObject)
268            return ((GenericObject) val).encode();
269        else
270            return val.toString();
271    }
272
273    /*
274     * (non-Javadoc)
275     * @see java.util.Map#clear()
276     */
277
278    public void clear() {
279        this.hmap.clear();
280    }
281
282    /*
283     * (non-Javadoc)
284     * @see java.util.Map#containsKey(java.lang.Object)
285     */
286    public boolean containsKey(Object key) {
287        return this.hmap.containsKey(key.toString().toLowerCase());
288    }
289
290    /*
291     * (non-Javadoc)
292     * @see java.util.Map#containsValue(java.lang.Object)
293     */
294    public boolean containsValue(Object value) {
295        return this.hmap.containsValue(value);
296    }
297
298    /*
299     * (non-Javadoc)
300     * @see java.util.Map#entrySet()
301     */
302    public Set<java.util.Map.Entry<String, NameValue>> entrySet() {
303        return this.hmap.entrySet();
304    }
305
306    /*
307     * (non-Javadoc)
308     * @see java.util.Map#get(java.lang.Object)
309     */
310    public NameValue get(Object key) {
311        return this.hmap.get(key.toString().toLowerCase());
312    }
313
314    /*
315     * (non-Javadoc)
316     * @see java.util.Map#keySet()
317     */
318    public Set<String> keySet() {
319        return this.hmap.keySet();
320    }
321
322    /*
323     * (non-Javadoc)
324     * @see java.util.Map#put(java.lang.Object, java.lang.Object)
325     */
326    public NameValue put(String name, NameValue nameValue) {
327        return this.hmap.put(name, nameValue);
328    }
329
330    public void putAll(Map<? extends String, ? extends NameValue> map) {
331        this.hmap.putAll(map);
332    }
333
334    /*
335     * (non-Javadoc)
336     * @see java.util.Map#remove(java.lang.Object)
337     */
338    public NameValue remove(Object key) {
339        return this.hmap.remove(key.toString().toLowerCase());
340    }
341
342    /*
343     * (non-Javadoc)
344     * @see java.util.Map#values()
345     */
346    public Collection<NameValue> values() {
347        return this.hmap.values();
348    }
349
350    @Override
351    public int hashCode() {
352        return this.hmap.keySet().hashCode();
353    }
354}
355