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.Map.Entry;
32
33/*
34 * Bug reports and fixes: Kirby Kiem, Jeroen van Bemmel.
35 */
36
37/**
38 * Generic structure for storing name-value pairs.
39 *
40 * @version 1.2
41 *
42 * @author M. Ranganathan <br/>
43 *
44 *
45 *
46 */
47public class NameValue extends GenericObject implements Entry<String,String> {
48
49    private static final long serialVersionUID = -1857729012596437950L;
50
51    protected boolean isQuotedString;
52
53    protected final boolean isFlagParameter;
54
55    private String separator;
56
57    private String quotes;
58
59    private String name;
60
61    private Object value;
62
63    public NameValue() {
64        name = null;
65        value = "";
66        separator = Separators.EQUALS;
67        this.quotes = "";
68        this.isFlagParameter = false;
69    }
70
71    /**
72     * New constructor, taking a boolean which is set if the NV pair is a flag
73     *
74     * @param n
75     * @param v
76     * @param isFlag
77     */
78    public NameValue(String n, Object v, boolean isFlag) {
79
80        // assert (v != null ); // I dont think this assertion is correct mranga
81
82        name = n;
83        value = v;
84        separator = Separators.EQUALS;
85        quotes = "";
86        this.isFlagParameter = isFlag;
87    }
88
89    /**
90     * Original constructor, sets isFlagParameter to 'false'
91     *
92     * @param n
93     * @param v
94     */
95    public NameValue(String n, Object v) {
96        this(n, v, false);
97    }
98
99    /**
100     * Set the separator for the encoding method below.
101     */
102    public void setSeparator(String sep) {
103        separator = sep;
104    }
105
106    /**
107     * A flag that indicates that doublequotes should be put around the value
108     * when encoded (for example name=value when value is doublequoted).
109     */
110    public void setQuotedValue() {
111        isQuotedString = true;
112        this.quotes = Separators.DOUBLE_QUOTE;
113    }
114
115    /**
116     * Return true if the value is quoted in doublequotes.
117     */
118    public boolean isValueQuoted() {
119        return isQuotedString;
120    }
121
122    public String getName() {
123        return name;
124    }
125
126    public Object getValueAsObject() {
127        return isFlagParameter ? "" : value; // never return null for flag
128                                                // params
129    }
130
131    /**
132     * Set the name member
133     */
134    public void setName(String n) {
135        name = n;
136    }
137
138    /**
139     * Set the value member
140     */
141    public void setValueAsObject(Object v) {
142        value = v;
143    }
144
145    /**
146     * Get the encoded representation of this namevalue object. Added
147     * doublequote for encoding doublequoted values.
148     *
149     * Bug: RFC3261 stipulates that an opaque parameter in authenticate header
150     * has to be:
151     * opaque              =  "opaque" EQUAL quoted-string
152     * so returning just the name is not acceptable. (e.g. LinkSys phones
153     * are picky about this)
154     *
155     * @since 1.0
156     * @return an encoded name value (eg. name=value) string.
157     */
158    public String encode() {
159        return encode(new StringBuffer()).toString();
160    }
161
162    public StringBuffer encode(StringBuffer buffer) {
163        if (name != null && value != null && !isFlagParameter) {
164            if (GenericObject.isMySubclass(value.getClass())) {
165                GenericObject gv = (GenericObject) value;
166                buffer.append(name).append(separator).append(quotes);
167                gv.encode(buffer);
168                buffer.append(quotes);
169                return buffer;
170            } else if (GenericObjectList.isMySubclass(value.getClass())) {
171                GenericObjectList gvlist = (GenericObjectList) value;
172                buffer.append(name).append(separator).append(gvlist.encode());
173                return buffer;
174            } else if ( value.toString().length() == 0) {
175                // opaque="" bug fix - pmusgrave
176                /*if (name.toString().equals(gov.nist.javax.sip.header.ParameterNames.OPAQUE))
177                    return name + separator + quotes + quotes;
178                else
179                    return name;*/
180                if ( this.isQuotedString ) {
181                    buffer.append(name).append(separator).append(quotes).append(quotes);
182                    return buffer;
183                } else {
184                    buffer.append(name).append(separator); // JvB: fix, case: "sip:host?subject="
185                    return buffer;
186                }
187            } else {
188                buffer.append(name).append(separator).append(quotes).append(value.toString()).append(quotes);
189                return buffer;
190            }
191        } else if (name == null && value != null) {
192            if (GenericObject.isMySubclass(value.getClass())) {
193                GenericObject gv = (GenericObject) value;
194                gv.encode(buffer);
195                return buffer;
196            } else if (GenericObjectList.isMySubclass(value.getClass())) {
197                GenericObjectList gvlist = (GenericObjectList) value;
198                buffer.append(gvlist.encode());
199                return buffer;
200            } else {
201                buffer.append(quotes).append(value.toString()).append(quotes);
202                return buffer;
203            }
204        } else if (name != null && (value == null || isFlagParameter)) {
205            buffer.append(name);
206            return buffer;
207        } else {
208            return buffer;
209        }
210    }
211
212    public Object clone() {
213        NameValue retval = (NameValue) super.clone();
214        if (value != null)
215            retval.value = makeClone(value);
216        return retval;
217    }
218
219    /**
220     * Equality comparison predicate.
221     */
222    public boolean equals(Object other) {
223        if (other == null ) return false;
224        if (!other.getClass().equals(this.getClass()))
225            return false;
226        NameValue that = (NameValue) other;
227        if (this == that)
228            return true;
229        if (this.name == null && that.name != null || this.name != null
230                && that.name == null)
231            return false;
232        if (this.name != null && that.name != null
233                && this.name.compareToIgnoreCase(that.name) != 0)
234            return false;
235        if (this.value != null && that.value == null || this.value == null
236                && that.value != null)
237            return false;
238        if (this.value == that.value)
239            return true;
240        if (value instanceof String) {
241            // Quoted string comparisions are case sensitive.
242            if (isQuotedString)
243                return this.value.equals(that.value);
244            String val = (String) this.value;
245            String val1 = (String) that.value;
246            return val.compareToIgnoreCase(val1) == 0;
247        } else
248            return this.value.equals(that.value);
249    }
250
251    /*
252     * (non-Javadoc)
253     * @see java.util.Map$Entry#getKey()
254     */
255    public String getKey() {
256
257        return this.name;
258    }
259
260    /*
261     * (non-Javadoc)
262     * @see java.util.Map$Entry#getValue()
263     */
264    public String getValue() {
265
266        return  value == null ? null : this.value.toString();
267    }
268
269    /*
270     * (non-Javadoc)
271     * @see java.util.Map$Entry#setValue(java.lang.Object)
272     */
273    public String setValue(String value) {
274        String retval = this.value == null ? null : value;
275        this.value = value;
276        return retval;
277
278    }
279
280    @Override
281    public int hashCode() {
282        return this.encode().toLowerCase().hashCode();
283    }
284
285}
286