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.javax.sip.header; 30 31 import gov.nist.core.GenericObject; 32 import gov.nist.core.Separators; 33 import gov.nist.javax.sip.header.ims.PrivacyHeader; 34 35 import javax.sip.header.Header; 36 import java.lang.reflect.Constructor; 37 import java.util.*; 38 39 /** 40 * 41 * This is the root class for all lists of SIP headers. It imbeds a 42 * SIPObjectList object and extends SIPHeader Lists of ContactSIPObjects etc. 43 * derive from this class. This supports homogeneous lists (all elements in the 44 * list are of the same class). We use this for building type homogeneous lists 45 * of SIPObjects that appear in SIPHeaders 46 * 47 * @version 1.2 $Revision: 1.15 $ $Date: 2005/10/09 18:47:53 48 */ 49 public abstract class SIPHeaderList<HDR extends SIPHeader> extends SIPHeader implements java.util.List<HDR>, Header { 50 51 private static boolean prettyEncode = false; 52 /** 53 * hlist field. 54 */ 55 protected List<HDR> hlist; 56 57 private Class<HDR> myClass; 58 getName()59 public String getName() { 60 return this.headerName; 61 } 62 63 SIPHeaderList()64 private SIPHeaderList() { 65 hlist = new LinkedList<HDR>(); 66 } 67 68 /** 69 * Constructor 70 * 71 * @param objclass 72 * Class to set 73 * @param hname 74 * String to set 75 */ SIPHeaderList(Class<HDR> objclass, String hname)76 protected SIPHeaderList(Class<HDR> objclass, String hname) { 77 this(); 78 this.headerName = hname; 79 this.myClass = objclass; 80 } 81 82 /** 83 * Concatenate the list of stuff that we are keeping around and also the 84 * text corresponding to these structures (that we parsed). 85 * 86 * @param objectToAdd 87 */ add(HDR objectToAdd)88 public boolean add(HDR objectToAdd) { 89 hlist.add((HDR)objectToAdd); 90 return true; 91 } 92 93 /** 94 * Concatenate the list of stuff that we are keeping around and also the 95 * text corresponding to these structures (that we parsed). 96 * 97 * @param obj 98 * Genericobject to set 99 */ addFirst(HDR obj)100 public void addFirst(HDR obj) { 101 hlist.add(0,(HDR) obj); 102 } 103 104 /** 105 * Add to this list. 106 * 107 * @param sipheader 108 * SIPHeader to add. 109 * @param top 110 * is true if we want to add to the top of the list. 111 */ add(HDR sipheader, boolean top)112 public void add(HDR sipheader, boolean top) { 113 if (top) 114 this.addFirst(sipheader); 115 else 116 this.add(sipheader); 117 } 118 119 /** 120 * Concatenate two compatible lists. This appends or prepends the new list 121 * to the end of this list. 122 * 123 * @param other 124 * SIPHeaderList to set 125 * @param topFlag 126 * flag which indicates which end to concatenate 127 * the lists. 128 * @throws IllegalArgumentException 129 * if the two lists are not compatible 130 */ concatenate(SIPHeaderList<HDR> other, boolean topFlag)131 public void concatenate(SIPHeaderList<HDR> other, boolean topFlag) 132 throws IllegalArgumentException { 133 if (!topFlag) { 134 this.addAll(other); 135 } else { 136 // add given items to the top end of the list. 137 this.addAll(0, other); 138 } 139 140 } 141 142 143 144 /** 145 * Encode a list of sip headers. Headers are returned in cannonical form. 146 * 147 * @return String encoded string representation of this list of headers. 148 * (Contains string append of each encoded header). 149 */ encode()150 public String encode() { 151 return encode(new StringBuffer()).toString(); 152 } 153 encode(StringBuffer buffer)154 public StringBuffer encode(StringBuffer buffer) { 155 if (hlist.isEmpty()) { 156 buffer.append(headerName).append(':').append(Separators.NEWLINE); 157 } 158 else { 159 // The following headers do not have comma separated forms for 160 // multiple headers. Thus, they must be encoded separately. 161 if (this.headerName.equals(SIPHeaderNames.WWW_AUTHENTICATE) 162 || this.headerName.equals(SIPHeaderNames.PROXY_AUTHENTICATE) 163 || this.headerName.equals(SIPHeaderNames.AUTHORIZATION) 164 || this.headerName.equals(SIPHeaderNames.PROXY_AUTHORIZATION) 165 || (prettyEncode && 166 (this.headerName.equals(SIPHeaderNames.VIA) || this.headerName.equals(SIPHeaderNames.ROUTE) || this.headerName.equals(SIPHeaderNames.RECORD_ROUTE))) // Less confusing to read 167 || this.getClass().equals( ExtensionHeaderList.class) ) { 168 ListIterator<HDR> li = hlist.listIterator(); 169 while (li.hasNext()) { 170 HDR sipheader = (HDR) li.next(); 171 sipheader.encode(buffer); 172 } 173 } else { 174 // These can be concatenated together in an comma separated 175 // list. 176 buffer.append(headerName).append(Separators.COLON).append(Separators.SP); 177 this.encodeBody(buffer); 178 buffer.append(Separators.NEWLINE); 179 } 180 } 181 return buffer; 182 } 183 184 /** 185 * Return a list of encoded strings (one for each sipheader). 186 * 187 * @return LinkedList containing encoded strings in this header list. an 188 * empty list is returned if this header list contains no sip 189 * headers. 190 */ 191 getHeadersAsEncodedStrings()192 public List<String> getHeadersAsEncodedStrings() { 193 List<String> retval = new LinkedList<String>(); 194 195 ListIterator<HDR> li = hlist.listIterator(); 196 while (li.hasNext()) { 197 Header sipheader = li.next(); 198 retval.add(sipheader.toString()); 199 200 } 201 202 return retval; 203 204 } 205 206 /** 207 * Get the first element of this list. 208 * 209 * @return SIPHeader first element of the list. 210 */ getFirst()211 public HDR getFirst() { 212 if (hlist == null || hlist.isEmpty()) 213 return null; 214 else 215 return hlist.get(0); 216 } 217 218 /** 219 * Get the last element of this list. 220 * 221 * @return SIPHeader last element of the list. 222 */ getLast()223 public HDR getLast() { 224 if (hlist == null || hlist.isEmpty()) 225 return null; 226 return hlist.get(hlist.size() - 1); 227 } 228 229 /** 230 * Get the class for the headers of this list. 231 * 232 * @return Class of header supported by this list. 233 */ getMyClass()234 public Class<HDR> getMyClass() { 235 return this.myClass; 236 } 237 238 /** 239 * Empty check 240 * 241 * @return boolean true if list is empty 242 */ isEmpty()243 public boolean isEmpty() { 244 return hlist.isEmpty(); 245 } 246 247 /** 248 * Get an initialized iterator for my imbedded list 249 * 250 * @return the generated ListIterator 251 */ listIterator()252 public ListIterator<HDR> listIterator() { 253 254 return hlist.listIterator(0); 255 } 256 257 /** 258 * Get the imbedded linked list. 259 * 260 * @return the imedded linked list of SIP headers. 261 */ getHeaderList()262 public List<HDR> getHeaderList() { 263 return this.hlist; 264 } 265 266 /** 267 * Get the list iterator for a given position. 268 * 269 * @param position 270 * position for the list iterator to return 271 * @return the generated list iterator 272 */ listIterator(int position)273 public ListIterator<HDR> listIterator(int position) { 274 return hlist.listIterator(position); 275 } 276 277 /** 278 * Remove the first element of this list. 279 */ removeFirst()280 public HDR removeFirst() { 281 if (hlist.size() != 0) { 282 return hlist.remove(0); 283 } 284 return null; 285 } 286 287 /** 288 * Remove the last element of this list. 289 */ removeLast()290 public HDR removeLast() { 291 if (hlist.size() != 0) { 292 return hlist.remove(hlist.size() - 1); 293 } 294 return null; 295 } 296 297 /** 298 * Remove a sip header from this list of sip headers. 299 * 300 * @param obj 301 * SIPHeader to remove 302 * @return boolean 303 */ remove(HDR obj)304 public boolean remove(HDR obj) { 305 if (hlist.size() == 0) 306 return false; 307 else 308 return hlist.remove(obj); 309 } 310 311 /** 312 * Set the root class for all objects inserted into my list (for assertion 313 * check) 314 * 315 * @param cl 316 * class to set 317 */ setMyClass(Class<HDR> cl)318 protected void setMyClass(Class<HDR> cl) { 319 this.myClass = cl; 320 } 321 322 /** 323 * convert to a string representation (for printing). 324 * 325 * @param indentation 326 * int to set 327 * @return String string representation of object (for printing). 328 */ debugDump(int indentation)329 public String debugDump(int indentation) { 330 stringRepresentation = ""; 331 String indent = new Indentation(indentation).getIndentation(); 332 333 String className = this.getClass().getName(); 334 sprint(indent + className); 335 sprint(indent + "{"); 336 337 for (Iterator<HDR> it = hlist.iterator(); it.hasNext();) { 338 HDR sipHeader = (HDR) it.next(); 339 sprint(indent + sipHeader.debugDump()); 340 } 341 sprint(indent + "}"); 342 return stringRepresentation; 343 } 344 345 /** 346 * convert to a string representation 347 * 348 * @return String 349 */ debugDump()350 public String debugDump() { 351 return debugDump(0); 352 } 353 354 /** 355 * Array conversion. 356 * 357 * @return SIPHeader [] 358 */ toArray()359 public Object[] toArray() { 360 return hlist.toArray(); 361 362 } 363 364 /** 365 * index of an element. 366 * 367 * @return index of the given element (-1) if element does not exist. 368 */ indexOf(GenericObject gobj)369 public int indexOf(GenericObject gobj) { 370 return hlist.indexOf(gobj); 371 } 372 373 /** 374 * insert at a location. 375 * 376 * @param index 377 * location where to add the sipHeader. 378 * @param sipHeader 379 * SIPHeader structure to add. 380 */ 381 add(int index, HDR sipHeader)382 public void add(int index, HDR sipHeader) 383 throws IndexOutOfBoundsException { 384 hlist.add(index, sipHeader); 385 } 386 387 /** 388 * Equality comparison operator. 389 * 390 * @param other 391 * the other object to compare with. true is returned iff the 392 * classes match and list of headers herein is equal to the list 393 * of headers in the target (order of the headers is not 394 * important). 395 */ 396 @SuppressWarnings("unchecked") equals(Object other)397 public boolean equals(Object other) { 398 399 if (other == this) 400 return true; 401 402 if (other instanceof SIPHeaderList) { 403 SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) other; 404 if (this.hlist == that.hlist) 405 return true; 406 else if (this.hlist == null) 407 return that.hlist == null || that.hlist.size() == 0; 408 return this.hlist.equals(that.hlist); 409 } 410 return false; 411 } 412 413 /** 414 * Template match against a template. null field in template indicates wild 415 * card match. 416 */ match(SIPHeaderList<?> template)417 public boolean match(SIPHeaderList<?> template) { 418 if (template == null) 419 return true; 420 if (!this.getClass().equals(template.getClass())) 421 return false; 422 SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) template; 423 if (this.hlist == that.hlist) 424 return true; 425 else if (this.hlist == null) 426 return false; 427 else { 428 429 for (Iterator<SIPHeader> it = that.hlist.iterator(); it.hasNext();) { 430 SIPHeader sipHeader = (SIPHeader) it.next(); 431 432 boolean found = false; 433 for (Iterator<HDR> it1 = this.hlist.iterator(); it1.hasNext() 434 && !found;) { 435 SIPHeader sipHeader1 = (SIPHeader) it1.next(); 436 found = sipHeader1.match(sipHeader); 437 } 438 if (!found) 439 return false; 440 } 441 return true; 442 } 443 } 444 445 446 /** 447 * make a clone of this header list. 448 * 449 * @return clone of this Header. 450 */ clone()451 public Object clone() { 452 try { 453 Class<?> clazz = this.getClass(); 454 455 Constructor<?> cons = clazz.getConstructor((Class[])null); 456 SIPHeaderList<HDR> retval = (SIPHeaderList<HDR>) cons.newInstance((Object[])null); 457 retval.headerName = this.headerName; 458 retval.myClass = this.myClass; 459 return retval.clonehlist(this.hlist); 460 } catch (Exception ex) { 461 throw new RuntimeException("Could not clone!", ex); 462 } 463 } 464 clonehlist(List<HDR> hlistToClone)465 protected final SIPHeaderList<HDR> clonehlist(List<HDR> hlistToClone) { 466 if (hlistToClone != null) { 467 for (Iterator<HDR> it = (Iterator<HDR>) hlistToClone.iterator(); it.hasNext();) { 468 Header h = it.next(); 469 this.hlist.add((HDR)h.clone()); 470 } 471 } 472 return this; 473 } 474 475 /** 476 * Get the number of headers in the list. 477 */ size()478 public int size() { 479 return hlist.size(); 480 } 481 482 /** 483 * Return true if this is a header list (overrides the base class method 484 * which returns false). 485 * 486 * @return true 487 */ isHeaderList()488 public boolean isHeaderList() { 489 return true; 490 } 491 492 /** 493 * Encode the body of this header (the stuff that follows headerName). A.K.A 494 * headerValue. This will not give a reasonable result for WWW-Authenticate, 495 * Authorization, Proxy-Authenticate and Proxy-Authorization and hence this 496 * is protected. 497 */ encodeBody()498 protected String encodeBody() { 499 return encodeBody(new StringBuffer()).toString(); 500 } 501 encodeBody(StringBuffer buffer)502 protected StringBuffer encodeBody(StringBuffer buffer) { 503 ListIterator<HDR> iterator = this.listIterator(); 504 while (true) { 505 SIPHeader sipHeader = (SIPHeader) iterator.next(); 506 if ( sipHeader == this ) throw new RuntimeException ("Unexpected circularity in SipHeaderList"); 507 sipHeader.encodeBody(buffer); 508 // if (body.equals("")) System.out.println("BODY == "); 509 if (iterator.hasNext()) { 510 if (!this.headerName.equals(PrivacyHeader.NAME)) 511 buffer.append(Separators.COMMA); 512 else 513 buffer.append(Separators.SEMICOLON); 514 continue; 515 } else 516 break; 517 518 } 519 return buffer; 520 } 521 addAll(Collection<? extends HDR> collection)522 public boolean addAll(Collection<? extends HDR> collection) { 523 return this.hlist.addAll(collection); 524 } 525 addAll(int index, Collection<? extends HDR> collection)526 public boolean addAll(int index, Collection<? extends HDR> collection) { 527 return this.hlist.addAll(index, collection); 528 529 } 530 containsAll(Collection<?> collection)531 public boolean containsAll(Collection<?> collection) { 532 return this.hlist.containsAll(collection); 533 } 534 535 536 537 clear()538 public void clear() { 539 this.hlist.clear(); 540 } 541 contains(Object header)542 public boolean contains(Object header) { 543 return this.hlist.contains(header); 544 } 545 546 547 /** 548 * Get the object at the specified location. 549 * 550 * @param index -- 551 * location from which to get the object. 552 * 553 */ get(int index)554 public HDR get(int index) { 555 return this.hlist.get(index); 556 } 557 558 /** 559 * Return the index of a given object. 560 * 561 * @param obj -- 562 * object whose index to compute. 563 */ indexOf(Object obj)564 public int indexOf(Object obj) { 565 return this.hlist.indexOf(obj); 566 } 567 568 /** 569 * Return the iterator to the imbedded list. 570 * 571 * @return iterator to the imbedded list. 572 * 573 */ 574 iterator()575 public java.util.Iterator<HDR> iterator() { 576 return this.hlist.listIterator(); 577 } 578 579 /** 580 * Get the last index of the given object. 581 * 582 * @param obj -- 583 * object whose index to find. 584 */ lastIndexOf(Object obj)585 public int lastIndexOf(Object obj) { 586 587 return this.hlist.lastIndexOf(obj); 588 } 589 590 /** 591 * Remove the given object. 592 * 593 * @param obj -- 594 * object to remove. 595 * 596 */ 597 remove(Object obj)598 public boolean remove(Object obj) { 599 600 return this.hlist.remove(obj); 601 } 602 603 /** 604 * Remove the object at a given index. 605 * 606 * @param index -- 607 * index at which to remove the object 608 */ 609 remove(int index)610 public HDR remove(int index) { 611 return this.hlist.remove(index); 612 } 613 614 /** 615 * Remove all the elements. 616 * @see List#removeAll(java.util.Collection) 617 */ removeAll(java.util.Collection<?> collection)618 public boolean removeAll(java.util.Collection<?> collection) { 619 return this.hlist.removeAll(collection); 620 } 621 622 623 /** 624 * @see List#retainAll(java.util.Collection) 625 * @param collection 626 */ retainAll(java.util.Collection<?> collection)627 public boolean retainAll(java.util.Collection<?> collection) { 628 return this.hlist.retainAll(collection); 629 } 630 631 /** 632 * Get a sublist of the list. 633 * 634 * @see List#subList(int, int) 635 */ subList(int index1, int index2)636 public java.util.List<HDR> subList(int index1, int index2) { 637 return this.hlist.subList(index1, index2); 638 639 } 640 641 /** 642 * @see Object#hashCode() 643 * @return -- the computed hashcode. 644 */ hashCode()645 public int hashCode() { 646 647 return this.headerName.hashCode(); 648 } 649 650 /** 651 * Set a SIPHeader at a particular position in the list. 652 * 653 * @see List#set(int, java.lang.Object) 654 */ set(int position, HDR sipHeader)655 public HDR set(int position, HDR sipHeader) { 656 657 return hlist.set(position, sipHeader); 658 659 } 660 661 setPrettyEncode(boolean flag)662 public static void setPrettyEncode(boolean flag) { 663 prettyEncode = flag; 664 } 665 666 toArray(T[] array)667 public <T> T[] toArray(T[] array) { 668 return this.hlist.toArray(array); 669 } 670 671 672 } 673