Home | History | Annotate | Download | only in header
      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 
     59     public String getName() {
     60         return this.headerName;
     61     }
     62 
     63 
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    150     public String encode() {
    151         return encode(new StringBuffer()).toString();
    152     }
    153 
    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 
    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      */
    211     public Header 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      */
    223     public Header 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      */
    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      */
    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      */
    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      */
    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      */
    273     public ListIterator<HDR> listIterator(int position) {
    274         return hlist.listIterator(position);
    275     }
    276 
    277     /**
    278      * Remove the first element of this list.
    279      */
    280     public void removeFirst() {
    281         if (hlist.size() != 0)
    282             hlist.remove(0);
    283 
    284     }
    285 
    286     /**
    287      * Remove the last element of this list.
    288      */
    289     public void removeLast() {
    290         if (hlist.size() != 0)
    291             hlist.remove(hlist.size() - 1);
    292     }
    293 
    294     /**
    295      * Remove a sip header from this list of sip headers.
    296      *
    297      * @param obj
    298      *            SIPHeader to remove
    299      * @return boolean
    300      */
    301     public boolean remove(HDR obj) {
    302         if (hlist.size() == 0)
    303             return false;
    304         else
    305             return hlist.remove(obj);
    306     }
    307 
    308     /**
    309      * Set the root class for all objects inserted into my list (for assertion
    310      * check)
    311      *
    312      * @param cl
    313      *            class to set
    314      */
    315     protected void setMyClass(Class<HDR> cl) {
    316         this.myClass = cl;
    317     }
    318 
    319     /**
    320      * convert to a string representation (for printing).
    321      *
    322      * @param indentation
    323      *            int to set
    324      * @return String string representation of object (for printing).
    325      */
    326     public String debugDump(int indentation) {
    327         stringRepresentation = "";
    328         String indent = new Indentation(indentation).getIndentation();
    329 
    330         String className = this.getClass().getName();
    331         sprint(indent + className);
    332         sprint(indent + "{");
    333 
    334         for (Iterator<HDR> it = hlist.iterator(); it.hasNext();) {
    335             HDR sipHeader = (HDR) it.next();
    336             sprint(indent + sipHeader.debugDump());
    337         }
    338         sprint(indent + "}");
    339         return stringRepresentation;
    340     }
    341 
    342     /**
    343      * convert to a string representation
    344      *
    345      * @return String
    346      */
    347     public String debugDump() {
    348         return debugDump(0);
    349     }
    350 
    351     /**
    352      * Array conversion.
    353      *
    354      * @return SIPHeader []
    355      */
    356     public Object[] toArray() {
    357         return hlist.toArray();
    358 
    359     }
    360 
    361     /**
    362      * index of an element.
    363      *
    364      * @return index of the given element (-1) if element does not exist.
    365      */
    366     public int indexOf(GenericObject gobj) {
    367         return hlist.indexOf(gobj);
    368     }
    369 
    370     /**
    371      * insert at a location.
    372      *
    373      * @param index
    374      *            location where to add the sipHeader.
    375      * @param sipHeader
    376      *            SIPHeader structure to add.
    377      */
    378 
    379     public void add(int index, HDR  sipHeader)
    380             throws IndexOutOfBoundsException {
    381         hlist.add(index, sipHeader);
    382     }
    383 
    384     /**
    385      * Equality comparison operator.
    386      *
    387      * @param other
    388      *            the other object to compare with. true is returned iff the
    389      *            classes match and list of headers herein is equal to the list
    390      *            of headers in the target (order of the headers is not
    391      *            important).
    392      */
    393     @SuppressWarnings("unchecked")
    394     public boolean equals(Object other) {
    395 
    396         if (other == this)
    397             return true;
    398 
    399         if (other instanceof SIPHeaderList) {
    400             SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) other;
    401             if (this.hlist == that.hlist)
    402                 return true;
    403             else if (this.hlist == null)
    404                 return that.hlist == null || that.hlist.size() == 0;
    405             return this.hlist.equals(that.hlist);
    406         }
    407         return false;
    408     }
    409 
    410     /**
    411      * Template match against a template. null field in template indicates wild
    412      * card match.
    413      */
    414     public boolean match(SIPHeaderList<?> template) {
    415         if (template == null)
    416             return true;
    417         if (!this.getClass().equals(template.getClass()))
    418             return false;
    419         SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) template;
    420         if (this.hlist == that.hlist)
    421             return true;
    422         else if (this.hlist == null)
    423             return false;
    424         else {
    425 
    426             for (Iterator<SIPHeader> it = that.hlist.iterator(); it.hasNext();) {
    427                 SIPHeader sipHeader = (SIPHeader) it.next();
    428 
    429                 boolean found = false;
    430                 for (Iterator<HDR> it1 = this.hlist.iterator(); it1.hasNext()
    431                         && !found;) {
    432                     SIPHeader sipHeader1 = (SIPHeader) it1.next();
    433                     found = sipHeader1.match(sipHeader);
    434                 }
    435                 if (!found)
    436                     return false;
    437             }
    438             return true;
    439         }
    440     }
    441 
    442 
    443     /**
    444      * make a clone of this header list.
    445      *
    446      * @return clone of this Header.
    447      */
    448     public Object clone() {
    449         try {
    450             Class<?> clazz = this.getClass();
    451 
    452             Constructor<?> cons = clazz.getConstructor((Class[])null);
    453             SIPHeaderList<HDR> retval = (SIPHeaderList<HDR>) cons.newInstance((Object[])null);
    454             retval.headerName = this.headerName;
    455             retval.myClass  = this.myClass;
    456             return retval.clonehlist(this.hlist);
    457         } catch (Exception ex) {
    458             throw new RuntimeException("Could not clone!", ex);
    459         }
    460     }
    461 
    462     protected final SIPHeaderList<HDR> clonehlist(List<HDR> hlistToClone) {
    463         if (hlistToClone != null) {
    464             for (Iterator<HDR> it = (Iterator<HDR>) hlistToClone.iterator(); it.hasNext();) {
    465                 Header h = it.next();
    466                 this.hlist.add((HDR)h.clone());
    467             }
    468         }
    469         return this;
    470     }
    471 
    472     /**
    473      * Get the number of headers in the list.
    474      */
    475     public int size() {
    476         return hlist.size();
    477     }
    478 
    479     /**
    480      * Return true if this is a header list (overrides the base class method
    481      * which returns false).
    482      *
    483      * @return true
    484      */
    485     public boolean isHeaderList() {
    486         return true;
    487     }
    488 
    489     /**
    490      * Encode the body of this header (the stuff that follows headerName). A.K.A
    491      * headerValue. This will not give a reasonable result for WWW-Authenticate,
    492      * Authorization, Proxy-Authenticate and Proxy-Authorization and hence this
    493      * is protected.
    494      */
    495     protected String encodeBody() {
    496         return encodeBody(new StringBuffer()).toString();
    497     }
    498 
    499     protected StringBuffer encodeBody(StringBuffer buffer) {
    500         ListIterator<HDR> iterator = this.listIterator();
    501         while (true) {
    502             SIPHeader sipHeader = (SIPHeader) iterator.next();
    503             if ( sipHeader == this ) throw new RuntimeException ("Unexpected circularity in SipHeaderList");
    504             sipHeader.encodeBody(buffer);
    505             // if (body.equals("")) System.out.println("BODY == ");
    506             if (iterator.hasNext()) {
    507                 if (!this.headerName.equals(PrivacyHeader.NAME))
    508                     buffer.append(Separators.COMMA);
    509                 else
    510                     buffer.append(Separators.SEMICOLON);
    511                 continue;
    512             } else
    513                 break;
    514 
    515         }
    516         return buffer;
    517     }
    518 
    519     public boolean addAll(Collection<? extends HDR> collection) {
    520         return this.hlist.addAll(collection);
    521     }
    522 
    523     public boolean addAll(int index, Collection<? extends HDR> collection) {
    524         return this.hlist.addAll(index, collection);
    525 
    526     }
    527 
    528     public boolean containsAll(Collection<?> collection) {
    529         return this.hlist.containsAll(collection);
    530     }
    531 
    532 
    533 
    534 
    535     public void clear() {
    536         this.hlist.clear();
    537     }
    538 
    539     public boolean contains(Object header) {
    540         return this.hlist.contains(header);
    541     }
    542 
    543 
    544     /**
    545      * Get the object at the specified location.
    546      *
    547      * @param index --
    548      *            location from which to get the object.
    549      *
    550      */
    551     public HDR get(int index) {
    552         return  this.hlist.get(index);
    553     }
    554 
    555     /**
    556      * Return the index of a given object.
    557      *
    558      * @param obj --
    559      *            object whose index to compute.
    560      */
    561     public int indexOf(Object obj) {
    562         return this.hlist.indexOf(obj);
    563     }
    564 
    565     /**
    566      * Return the iterator to the imbedded list.
    567      *
    568      * @return iterator to the imbedded list.
    569      *
    570      */
    571 
    572     public java.util.Iterator<HDR> iterator() {
    573         return this.hlist.listIterator();
    574     }
    575 
    576     /**
    577      * Get the last index of the given object.
    578      *
    579      * @param obj --
    580      *            object whose index to find.
    581      */
    582     public int lastIndexOf(Object obj) {
    583 
    584         return this.hlist.lastIndexOf(obj);
    585     }
    586 
    587     /**
    588      * Remove the given object.
    589      *
    590      * @param obj --
    591      *            object to remove.
    592      *
    593      */
    594 
    595     public boolean remove(Object obj) {
    596 
    597         return this.hlist.remove(obj);
    598     }
    599 
    600     /**
    601      * Remove the object at a given index.
    602      *
    603      * @param index --
    604      *            index at which to remove the object
    605      */
    606 
    607     public HDR remove(int index) {
    608         return this.hlist.remove(index);
    609     }
    610 
    611     /**
    612      * Remove all the elements.
    613      * @see List#removeAll(java.util.Collection)
    614      */
    615     public boolean removeAll(java.util.Collection<?> collection) {
    616         return this.hlist.removeAll(collection);
    617     }
    618 
    619 
    620     /**
    621      * @see List#retainAll(java.util.Collection)
    622      * @param collection
    623      */
    624     public boolean retainAll(java.util.Collection<?> collection) {
    625         return this.hlist.retainAll(collection);
    626     }
    627 
    628     /**
    629      * Get a sublist of the list.
    630      *
    631      * @see List#subList(int, int)
    632      */
    633     public java.util.List<HDR> subList(int index1, int index2) {
    634         return this.hlist.subList(index1, index2);
    635 
    636     }
    637 
    638     /**
    639      * @see Object#hashCode()
    640      * @return -- the computed hashcode.
    641      */
    642     public int hashCode() {
    643 
    644         return this.headerName.hashCode();
    645     }
    646 
    647     /**
    648      * Set a SIPHeader at a particular position in the list.
    649      *
    650      * @see List#set(int, java.lang.Object)
    651      */
    652     public HDR set(int position, HDR sipHeader) {
    653 
    654         return hlist.set(position, sipHeader);
    655 
    656     }
    657 
    658 
    659     public static void setPrettyEncode(boolean flag) {
    660         prettyEncode = flag;
    661     }
    662 
    663 
    664     public <T> T[] toArray(T[] array) {
    665         return this.hlist.toArray(array);
    666     }
    667 
    668 
    669 }
    670