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.*; 32import java.io.Serializable; 33 34/** 35 * Implements a homogenous consistent linked list. All the objects in the linked 36 * list must derive from the same root class. This is a useful constraint to 37 * place on our code as this property is invariant.The list is created with the 38 * superclass which can be specified as either a class name or a Class. 39 * 40 * @version 1.2 41 * 42 * @author M. Ranganathan <br/> 43 * 44 * 45 * 46 */ 47public abstract class GenericObjectList extends LinkedList<GenericObject> implements 48 Serializable, Cloneable{ 49 // Useful constants. 50 protected static final String SEMICOLON = Separators.SEMICOLON; 51 52 protected static final String COLON = Separators.COLON; 53 54 protected static final String COMMA = Separators.COMMA; 55 56 protected static final String SLASH = Separators.SLASH; 57 58 protected static final String SP = Separators.SP; 59 60 protected static final String EQUALS = Separators.EQUALS; 61 62 protected static final String STAR = Separators.STAR; 63 64 protected static final String NEWLINE = Separators.NEWLINE; 65 66 protected static final String RETURN = Separators.RETURN; 67 68 protected static final String LESS_THAN = Separators.LESS_THAN; 69 70 protected static final String GREATER_THAN = Separators.GREATER_THAN; 71 72 protected static final String AT = Separators.AT; 73 74 protected static final String DOT = Separators.DOT; 75 76 protected static final String QUESTION = Separators.QUESTION; 77 78 protected static final String POUND = Separators.POUND; 79 80 protected static final String AND = Separators.AND; 81 82 protected static final String LPAREN = Separators.LPAREN; 83 84 protected static final String RPAREN = Separators.RPAREN; 85 86 protected static final String DOUBLE_QUOTE = Separators.DOUBLE_QUOTE; 87 88 protected static final String QUOTE = Separators.QUOTE; 89 90 protected static final String HT = Separators.HT; 91 92 protected static final String PERCENT = Separators.PERCENT; 93 94 protected int indentation; 95 96 protected String listName; // For debugging 97 98 private ListIterator<? extends GenericObject> myListIterator; 99 100 private String stringRep; 101 102 protected Class<?> myClass; 103 104 protected String separator; 105 106 protected String getIndentation() { 107 char[] chars = new char[indentation]; 108 java.util.Arrays.fill(chars, ' '); 109 return new String(chars); 110 } 111 112 /** 113 * Return true if this supports reflection based cloning. 114 */ 115 protected static boolean isCloneable(Object obj) { 116 return obj instanceof Cloneable; 117 } 118 119 public static boolean isMySubclass(Class<?> other) { 120 return GenericObjectList.class.isAssignableFrom(other); 121 122 } 123 124 /** 125 * Makes a deep clone of this list. 126 */ 127 public Object clone() { 128 GenericObjectList retval = (GenericObjectList) super.clone(); 129 for (ListIterator<GenericObject> iter = retval.listIterator(); iter.hasNext();) { 130 GenericObject obj = (GenericObject) ((GenericObject) iter.next()) 131 .clone(); 132 iter.set(obj); 133 } 134 return retval; 135 } 136 137 138 139 public void setMyClass(Class cl) { 140 myClass = cl; 141 } 142 143 protected GenericObjectList() { 144 super(); 145 listName = null; 146 stringRep = ""; 147 separator = ";"; 148 } 149 150 protected GenericObjectList(String lname) { 151 this(); 152 listName = lname; 153 } 154 155 /** 156 * A Constructor which takes a list name and a class name (for assertion 157 * checking). 158 */ 159 160 protected GenericObjectList(String lname, String classname) { 161 this(lname); 162 try { 163 myClass = Class.forName(classname); 164 } catch (ClassNotFoundException ex) { 165 InternalErrorHandler.handleException(ex); 166 } 167 168 } 169 170 /** 171 * A Constructor which takes a list name and a class (for assertion 172 * checking). 173 */ 174 175 protected GenericObjectList(String lname, Class objclass) { 176 this(lname); 177 myClass = objclass; 178 } 179 180 /** 181 * Traverse the list given a list iterator 182 */ 183 protected GenericObject next(ListIterator iterator) { 184 try { 185 return (GenericObject) iterator.next(); 186 } catch (NoSuchElementException ex) { 187 return null; 188 } 189 } 190 191 /** 192 * This is the default list iterator.This will not handle nested list 193 * traversal. 194 */ 195 protected GenericObject first() { 196 myListIterator = this.listIterator(0); 197 try { 198 return (GenericObject) myListIterator.next(); 199 } catch (NoSuchElementException ex) { 200 return null; 201 } 202 } 203 204 /** 205 * Fetch the next object from the list based on the default list iterator 206 */ 207 protected GenericObject next() { 208 if (myListIterator == null) { 209 myListIterator = this.listIterator(0); 210 } 211 try { 212 return (GenericObject) myListIterator.next(); 213 } catch (NoSuchElementException ex) { 214 myListIterator = null; 215 return null; 216 } 217 } 218 219 /** 220 * Concatenate two compatible header lists, adding the argument to the tail 221 * end of this list. 222 * 223 * @param 224 * topFlag </var> set to true to add items to top of list 225 */ 226 protected void concatenate(GenericObjectList objList) { 227 concatenate(objList, false); 228 } 229 230 /** 231 * Concatenate two compatible header lists, adding the argument either to 232 * the beginning or the tail end of this list. A type check is done before 233 * concatenation. 234 * 235 * @param 236 * topFlag </var> set to true to add items to top of list else 237 * add them to the tail end of the list. 238 */ 239 protected void concatenate(GenericObjectList objList, boolean topFlag) { 240 if (!topFlag) { 241 this.addAll(objList); 242 } else { 243 // add given items to the top end of the list. 244 this.addAll(0, objList); 245 } 246 } 247 248 /** 249 * string formatting function. 250 */ 251 252 private void sprint(String s) { 253 if (s == null) { 254 stringRep += getIndentation(); 255 stringRep += "<null>\n"; 256 return; 257 } 258 259 if (s.compareTo("}") == 0 || s.compareTo("]") == 0) { 260 indentation--; 261 } 262 stringRep += getIndentation(); 263 stringRep += s; 264 stringRep += "\n"; 265 if (s.compareTo("{") == 0 || s.compareTo("[") == 0) { 266 indentation++; 267 } 268 } 269 270 /** 271 * Convert this list of headers to a formatted string. 272 */ 273 274 public String debugDump() { 275 stringRep = ""; 276 Object obj = this.first(); 277 if (obj == null) 278 return "<null>"; 279 sprint("listName:"); 280 sprint(listName); 281 sprint("{"); 282 while (obj != null) { 283 sprint("["); 284 sprint(((GenericObject) obj).debugDump(this.indentation)); 285 obj = next(); 286 sprint("]"); 287 } 288 sprint("}"); 289 return stringRep; 290 } 291 292 /** 293 * Convert this list of headers to a string (for printing) with an 294 * indentation given. 295 */ 296 297 public String debugDump(int indent) { 298 int save = indentation; 299 indentation = indent; 300 String retval = this.debugDump(); 301 indentation = save; 302 return retval; 303 } 304 305 public void addFirst(GenericObject objToAdd) { 306 if (myClass == null) { 307 myClass = objToAdd.getClass(); 308 } else { 309 super.addFirst(objToAdd); 310 } 311 } 312 313 /** 314 * Do a merge of the GenericObjects contained in this list with the 315 * GenericObjects in the mergeList. Note that this does an inplace 316 * modification of the given list. This does an object by object merge of 317 * the given objects. 318 * 319 * @param mergeList 320 * is the list of Generic objects that we want to do an object by 321 * object merge with. Note that no new objects are added to this 322 * list. 323 * 324 */ 325 326 public void mergeObjects(GenericObjectList mergeList) { 327 328 if (mergeList == null) 329 return; 330 Iterator it1 = this.listIterator(); 331 Iterator it2 = mergeList.listIterator(); 332 while (it1.hasNext()) { 333 GenericObject outerObj = (GenericObject) it1.next(); 334 while (it2.hasNext()) { 335 Object innerObj = it2.next(); 336 outerObj.merge(innerObj); 337 } 338 } 339 } 340 341 /** 342 * Encode the list in semicolon separated form. 343 * 344 * @return an encoded string containing the objects in this list. 345 * @since v1.0 346 */ 347 public String encode() { 348 if (this.isEmpty()) 349 return ""; 350 StringBuffer encoding = new StringBuffer(); 351 ListIterator iterator = this.listIterator(); 352 if (iterator.hasNext()) { 353 while (true) { 354 Object obj = iterator.next(); 355 if (obj instanceof GenericObject) { 356 GenericObject gobj = (GenericObject) obj; 357 encoding.append(gobj.encode()); 358 } else { 359 encoding.append(obj.toString()); 360 } 361 if (iterator.hasNext()) 362 encoding.append(separator); 363 else 364 break; 365 } 366 } 367 return encoding.toString(); 368 } 369 370 /** 371 * Alias for the encode function above. 372 */ 373 public String toString() { 374 return this.encode(); 375 } 376 377 /** 378 * Set the separator (for encoding the list) 379 * 380 * @since v1.0 381 * @param sep 382 * is the new seperator (default is semicolon) 383 */ 384 public void setSeparator(String sep) { 385 separator = sep; 386 } 387 388 /** 389 * Hash code. We never expect to put this in a hash table so return a constant. 390 */ 391 public int hashCode() { return 42; } 392 393 /** 394 * Equality checking predicate. 395 * 396 * @param other 397 * is the object to compare ourselves to. 398 * @return true if the objects are equal. 399 */ 400 public boolean equals(Object other) { 401 if (other == null ) return false; 402 if (!this.getClass().equals(other.getClass())) 403 return false; 404 GenericObjectList that = (GenericObjectList) other; 405 if (this.size() != that.size()) 406 return false; 407 ListIterator myIterator = this.listIterator(); 408 while (myIterator.hasNext()) { 409 Object myobj = myIterator.next(); 410 ListIterator hisIterator = that.listIterator(); 411 try { 412 while (true) { 413 Object hisobj = hisIterator.next(); 414 if (myobj.equals(hisobj)) 415 break; 416 } 417 } catch (NoSuchElementException ex) { 418 return false; 419 } 420 } 421 ListIterator hisIterator = that.listIterator(); 422 while (hisIterator.hasNext()) { 423 Object hisobj = hisIterator.next(); 424 myIterator = this.listIterator(); 425 try { 426 while (true) { 427 Object myobj = myIterator.next(); 428 if (hisobj.equals(myobj)) 429 break; 430 } 431 } catch (NoSuchElementException ex) { 432 return false; 433 } 434 } 435 return true; 436 } 437 438 /** 439 * Match with a template (return true if we have a superset of the given 440 * template. This can be used for partial match (template matching of SIP 441 * objects). Note -- this implementation is not unnecessarily efficient :-) 442 * 443 * @param other 444 * template object to compare against. 445 */ 446 447 public boolean match(Object other) { 448 if (!this.getClass().equals(other.getClass())) 449 return false; 450 GenericObjectList that = (GenericObjectList) other; 451 ListIterator hisIterator = that.listIterator(); 452 outer: while (hisIterator.hasNext()) { 453 Object hisobj = hisIterator.next(); 454 Object myobj = null; 455 ListIterator myIterator = this.listIterator(); 456 while (myIterator.hasNext()) { 457 myobj = myIterator.next(); 458 if (myobj instanceof GenericObject) 459 System.out.println("Trying to match = " 460 + ((GenericObject) myobj).encode()); 461 if (GenericObject.isMySubclass(myobj.getClass()) 462 && ((GenericObject) myobj).match(hisobj)) 463 break outer; 464 else if (GenericObjectList.isMySubclass(myobj.getClass()) 465 && ((GenericObjectList) myobj).match(hisobj)) 466 break outer; 467 } 468 System.out.println(((GenericObject) hisobj).encode()); 469 return false; 470 } 471 return true; 472 } 473} 474