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 *******************************************************************************/ 29 package gov.nist.core; 30 31 import 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 */ 47 public 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