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.javax.sip.header; 30import gov.nist.core.GenericObject; 31import gov.nist.core.GenericObjectList; 32import gov.nist.core.InternalErrorHandler; 33 34import java.lang.reflect.Field; 35import java.lang.reflect.Modifier; 36 37/** 38 * Root class for all singleton objects in this package: 39 * specializes the gov.nist.sip.header.GenericObject class for SIPHeader 40 * related objects. 41 * 42 * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:57:38 $ 43 * 44 * @author M. Ranganathan <br/> 45 * 46 * 47 * 48 */ 49 50public abstract class SIPObject extends GenericObject { 51 52 /** default Constructor 53 */ 54 protected SIPObject() { 55 super(); 56 } 57 58 59 60 /** Debug function 61 */ 62 public void dbgPrint() { 63 super.dbgPrint(); 64 } 65 66 /** Encode the header into a String. 67 * @return String 68 */ 69 public abstract String encode(); 70 71 /** Encode the header into the given StringBuffer. 72 * Default implemation calls encode(). 73 */ 74 public StringBuffer encode(StringBuffer buffer) { 75 return buffer.append(encode()); 76 } 77 78 /** 79 * An introspection based equality predicate for SIPObjects. 80 *@param other the other object to test against. 81 */ 82 public boolean equals(Object other) { 83 if (!this.getClass().equals(other.getClass())) 84 return false; 85 SIPObject that = (SIPObject) other; 86 Class myclass = this.getClass(); 87 Class hisclass = other.getClass(); 88 while (true) { 89 Field[] fields = myclass.getDeclaredFields(); 90 if (!hisclass.equals(myclass)) 91 return false; 92 Field[] hisfields = hisclass.getDeclaredFields(); 93 for (int i = 0; i < fields.length; i++) { 94 Field f = fields[i]; 95 Field g = hisfields[i]; 96 // Only print protected and public members. 97 int modifier = f.getModifiers(); 98 if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) 99 continue; 100 Class fieldType = f.getType(); 101 String fieldName = f.getName(); 102 if (fieldName.compareTo("stringRepresentation") == 0) { 103 continue; 104 } 105 if (fieldName.compareTo("indentation") == 0) { 106 continue; 107 } 108 try { 109 // Primitive fields are printed with type: value 110 if (fieldType.isPrimitive()) { 111 String fname = fieldType.toString(); 112 if (fname.compareTo("int") == 0) { 113 if (f.getInt(this) != g.getInt(that)) 114 return false; 115 } else if (fname.compareTo("short") == 0) { 116 if (f.getShort(this) != g.getShort(that)) 117 return false; 118 } else if (fname.compareTo("char") == 0) { 119 if (f.getChar(this) != g.getChar(that)) 120 return false; 121 } else if (fname.compareTo("long") == 0) { 122 if (f.getLong(this) != g.getLong(that)) 123 return false; 124 } else if (fname.compareTo("boolean") == 0) { 125 if (f.getBoolean(this) != g.getBoolean(that)) 126 return false; 127 } else if (fname.compareTo("double") == 0) { 128 if (f.getDouble(this) != g.getDouble(that)) 129 return false; 130 } else if (fname.compareTo("float") == 0) { 131 if (f.getFloat(this) != g.getFloat(that)) 132 return false; 133 } 134 } else if (g.get(that) == f.get(this)) 135 continue; 136 else if (f.get(this) == null && g.get(that) != null) 137 return false; 138 else if (g.get(that) == null && f.get(this) != null) 139 return false; 140 else if (!f.get(this).equals(g.get(that))) 141 return false; 142 } catch (IllegalAccessException ex1) { 143 System.out.println("accessed field " + fieldName); 144 System.out.println("modifier " + modifier); 145 System.out.println("modifier.private " + Modifier.PRIVATE); 146 InternalErrorHandler.handleException(ex1); 147 } 148 } 149 if (myclass.equals(SIPObject.class)) 150 break; 151 else { 152 myclass = myclass.getSuperclass(); 153 hisclass = hisclass.getSuperclass(); 154 } 155 } 156 return true; 157 } 158 159 /** An introspection based predicate matching using a template 160 * object. Allows for partial match of two protocl Objects. 161 * You can set a generalized matcher (using regular expressions 162 * for example) by implementing the Match interface and registering 163 * it with the template. 164 *@param other the match pattern to test against. The match object 165 * has to be of the same type (class). Primitive types 166 * and non-sip fields that are non null are matched for equality. 167 * Null in any field matches anything. Some book-keeping fields 168 * are ignored when making the comparison. 169 * 170 */ 171 public boolean match(Object other) { 172 if (other == null) { 173 return true; 174 } 175 176 if (!this.getClass().equals(other.getClass())) 177 return false; 178 GenericObject that = (GenericObject) other; 179 Class myclass = this.getClass(); 180 Class hisclass = other.getClass(); 181 while (true) { 182 Field[] fields = myclass.getDeclaredFields(); 183 Field[] hisfields = hisclass.getDeclaredFields(); 184 for (int i = 0; i < fields.length; i++) { 185 Field f = fields[i]; 186 Field g = hisfields[i]; 187 // Only print protected and public members. 188 int modifier = f.getModifiers(); 189 if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) 190 continue; 191 Class fieldType = f.getType(); 192 String fieldName = f.getName(); 193 if (fieldName.compareTo("stringRepresentation") == 0) { 194 continue; 195 } 196 if (fieldName.compareTo("indentation") == 0) { 197 continue; 198 } 199 try { 200 if (fieldType.isPrimitive()) { 201 String fname = fieldType.toString(); 202 if (fname.compareTo("int") == 0) { 203 if (f.getInt(this) != g.getInt(that)) 204 return false; 205 } else if (fname.compareTo("short") == 0) { 206 if (f.getShort(this) != g.getShort(that)) 207 return false; 208 } else if (fname.compareTo("char") == 0) { 209 if (f.getChar(this) != g.getChar(that)) 210 return false; 211 } else if (fname.compareTo("long") == 0) { 212 if (f.getLong(this) != g.getLong(that)) 213 return false; 214 } else if (fname.compareTo("boolean") == 0) { 215 if (f.getBoolean(this) != g.getBoolean(that)) 216 return false; 217 } else if (fname.compareTo("double") == 0) { 218 if (f.getDouble(this) != g.getDouble(that)) 219 return false; 220 } else if (fname.compareTo("float") == 0) { 221 if (f.getFloat(this) != g.getFloat(that)) 222 return false; 223 } else { 224 InternalErrorHandler.handleException( 225 "unknown type"); 226 } 227 } else { 228 Object myObj = f.get(this); 229 Object hisObj = g.get(that); 230 if (hisObj != null && myObj == null) 231 return false; 232 else if (hisObj == null && myObj != null) 233 continue; 234 else if (hisObj == null && myObj == null) 235 continue; 236 else if ( 237 hisObj instanceof java.lang.String 238 && myObj instanceof java.lang.String) { 239 if ((((String) hisObj).trim()).equals("")) 240 continue; 241 if (((String) myObj) 242 .compareToIgnoreCase((String) hisObj) 243 != 0) 244 return false; 245 } else if ( 246 hisObj != null 247 && GenericObject.isMySubclass(myObj.getClass()) 248 && GenericObject.isMySubclass(hisObj.getClass()) 249 && myObj.getClass().equals(hisObj.getClass()) 250 && ((GenericObject) hisObj).getMatcher() 251 != null) { 252 String myObjEncoded = 253 ((GenericObject) myObj).encode(); 254 boolean retval = 255 ((GenericObject) hisObj).getMatcher().match( 256 myObjEncoded); 257 if (!retval) 258 return false; 259 } else if ( 260 GenericObject.isMySubclass(myObj.getClass()) 261 && !((GenericObject) myObj).match(hisObj)) 262 return false; 263 else if ( 264 GenericObjectList.isMySubclass(myObj.getClass()) 265 && !((GenericObjectList) myObj).match(hisObj)) 266 return false; 267 268 } 269 } catch (IllegalAccessException ex1) { 270 InternalErrorHandler.handleException(ex1); 271 } 272 } 273 if (myclass.equals(SIPObject.class)) 274 break; 275 else { 276 myclass = myclass.getSuperclass(); 277 hisclass = hisclass.getSuperclass(); 278 } 279 } 280 return true; 281 } 282 283 /** 284 * An introspection based string formatting method. We need this because 285 * in this package (although it is an exact duplicate of the one in 286 * the superclass) because it needs to access the protected members 287 * of the other objects in this class. 288 * @return String 289 */ 290 public String debugDump() { 291 stringRepresentation = ""; 292 Class myclass = getClass(); 293 sprint(myclass.getName()); 294 sprint("{"); 295 Field[] fields = myclass.getDeclaredFields(); 296 for (int i = 0; i < fields.length; i++) { 297 Field f = fields[i]; 298 // Only print protected and public members. 299 int modifier = f.getModifiers(); 300 if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) 301 continue; 302 Class fieldType = f.getType(); 303 String fieldName = f.getName(); 304 if (fieldName.compareTo("stringRepresentation") == 0) { 305 // avoid nasty recursions... 306 continue; 307 } 308 if (fieldName.compareTo("indentation") == 0) { 309 // formatting stuff - not relevant here. 310 continue; 311 } 312 sprint(fieldName + ":"); 313 try { 314 // Primitive fields are printed with type: value 315 if (fieldType.isPrimitive()) { 316 String fname = fieldType.toString(); 317 sprint(fname + ":"); 318 if (fname.compareTo("int") == 0) { 319 int intfield = f.getInt(this); 320 sprint(intfield); 321 } else if (fname.compareTo("short") == 0) { 322 short shortField = f.getShort(this); 323 sprint(shortField); 324 } else if (fname.compareTo("char") == 0) { 325 char charField = f.getChar(this); 326 sprint(charField); 327 } else if (fname.compareTo("long") == 0) { 328 long longField = f.getLong(this); 329 sprint(longField); 330 } else if (fname.compareTo("boolean") == 0) { 331 boolean booleanField = f.getBoolean(this); 332 sprint(booleanField); 333 } else if (fname.compareTo("double") == 0) { 334 double doubleField = f.getDouble(this); 335 sprint(doubleField); 336 } else if (fname.compareTo("float") == 0) { 337 float floatField = f.getFloat(this); 338 sprint(floatField); 339 } 340 } else if (GenericObject.class.isAssignableFrom(fieldType)) { 341 if (f.get(this) != null) { 342 sprint( 343 ((GenericObject) f.get(this)).debugDump( 344 indentation + 1)); 345 } else { 346 sprint("<null>"); 347 } 348 349 } else if ( 350 GenericObjectList.class.isAssignableFrom(fieldType)) { 351 if (f.get(this) != null) { 352 sprint( 353 ((GenericObjectList) f.get(this)).debugDump( 354 indentation + 1)); 355 } else { 356 sprint("<null>"); 357 } 358 359 } else { 360 // Dont do recursion on things that are not 361 // of our header type... 362 if (f.get(this) != null) { 363 sprint(f.get(this).getClass().getName() + ":"); 364 } else { 365 sprint(fieldType.getName() + ":"); 366 } 367 368 sprint("{"); 369 if (f.get(this) != null) { 370 sprint(f.get(this).toString()); 371 } else { 372 sprint("<null>"); 373 } 374 sprint("}"); 375 } 376 } catch (IllegalAccessException ex1) { 377 continue; // we are accessing a private field... 378 } 379 } 380 sprint("}"); 381 return stringRepresentation; 382 } 383 384 /** 385 * Formatter with a given starting indentation (for nested structs). 386 * @param indent int to set 387 * @return String 388 */ 389 public String debugDump(int indent) { 390 int save = indentation; 391 indentation = indent; 392 String retval = this.debugDump(); 393 indentation = save; 394 return retval; 395 } 396 397 398 public String toString() { 399 return this.encode(); 400 } 401 402} 403