/* * Conditions Of Use * * This software was developed by employees of the National Institute of * Standards and Technology (NIST), an agency of the Federal Government. * Pursuant to title 15 Untied States Code Section 105, works of NIST * employees are not subject to copyright protection in the United States * and are considered to be in the public domain. As a result, a formal * license is not needed to use the software. * * This software is provided by NIST as a service and is expressly * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT * AND DATA ACCURACY. NIST does not warrant or make any representations * regarding the use of the software or the results thereof, including but * not limited to the correctness, accuracy, reliability or usefulness of * the software. * * Permission to use this software is contingent upon your acceptance * of the terms of this agreement * * . * */ /******************************************************************************* * Product of NIST/ITL Advanced Networking Technologies Division (ANTD). * ******************************************************************************/ package gov.nist.javax.sip.header; import gov.nist.core.GenericObject; import gov.nist.core.Separators; import gov.nist.javax.sip.header.ims.PrivacyHeader; import javax.sip.header.Header; import java.lang.reflect.Constructor; import java.util.*; /** * * This is the root class for all lists of SIP headers. It imbeds a * SIPObjectList object and extends SIPHeader Lists of ContactSIPObjects etc. * derive from this class. This supports homogeneous lists (all elements in the * list are of the same class). We use this for building type homogeneous lists * of SIPObjects that appear in SIPHeaders * * @version 1.2 $Revision: 1.16 $ $Date: 2005/10/09 18:47:53 */ public abstract class SIPHeaderList<HDR extends SIPHeader> extends SIPHeader implements java.util.List<HDR>, Header { private static boolean prettyEncode = false; /** * hlist field. */ protected List<HDR> hlist; private Class<HDR> myClass; public String getName() { return this.headerName; } private SIPHeaderList() { hlist = new LinkedList<HDR>(); } /** * Constructor * * @param objclass * Class to set * @param hname * String to set */ protected SIPHeaderList(Class<HDR> objclass, String hname) { this(); this.headerName = hname; this.myClass = objclass; } /** * Concatenate the list of stuff that we are keeping around and also the * text corresponding to these structures (that we parsed). * * @param objectToAdd */ public boolean add(HDR objectToAdd) { hlist.add((HDR)objectToAdd); return true; } /** * Concatenate the list of stuff that we are keeping around and also the * text corresponding to these structures (that we parsed). * * @param obj * Genericobject to set */ public void addFirst(HDR obj) { hlist.add(0,(HDR) obj); } /** * Add to this list. * * @param sipheader * SIPHeader to add. * @param top * is true if we want to add to the top of the list. */ public void add(HDR sipheader, boolean top) { if (top) this.addFirst(sipheader); else this.add(sipheader); } /** * Concatenate two compatible lists. This appends or prepends the new list * to the end of this list. * * @param other * SIPHeaderList to set * @param topFlag * flag which indicates which end to concatenate * the lists. * @throws IllegalArgumentException * if the two lists are not compatible */ public void concatenate(SIPHeaderList<HDR> other, boolean topFlag) throws IllegalArgumentException { if (!topFlag) { this.addAll(other); } else { // add given items to the top end of the list. this.addAll(0, other); } } /** * Encode a list of sip headers. Headers are returned in cannonical form. * * @return String encoded string representation of this list of headers. * (Contains string append of each encoded header). */ public String encode() { return encode(new StringBuilder()).toString(); } public StringBuilder encode(StringBuilder buffer) { if (hlist.isEmpty()) { buffer.append(headerName).append(':').append(Separators.NEWLINE); } else { // The following headers do not have comma separated forms for // multiple headers. Thus, they must be encoded separately. if (this.headerName.equals(SIPHeaderNames.WWW_AUTHENTICATE) || this.headerName.equals(SIPHeaderNames.PROXY_AUTHENTICATE) || this.headerName.equals(SIPHeaderNames.AUTHORIZATION) || this.headerName.equals(SIPHeaderNames.PROXY_AUTHORIZATION) || (prettyEncode && (this.headerName.equals(SIPHeaderNames.VIA) || this.headerName.equals(SIPHeaderNames.ROUTE) || this.headerName.equals(SIPHeaderNames.RECORD_ROUTE))) // Less confusing to read || this.getClass().equals( ExtensionHeaderList.class) ) { ListIterator<HDR> li = hlist.listIterator(); while (li.hasNext()) { HDR sipheader = (HDR) li.next(); sipheader.encode(buffer); } } else { // These can be concatenated together in an comma separated // list. buffer.append(headerName).append(Separators.COLON).append(Separators.SP); this.encodeBody(buffer); buffer.append(Separators.NEWLINE); } } return buffer; } /** * Return a list of encoded strings (one for each sipheader). * * @return LinkedList containing encoded strings in this header list. an * empty list is returned if this header list contains no sip * headers. */ public List<String> getHeadersAsEncodedStrings() { List<String> retval = new LinkedList<String>(); ListIterator<HDR> li = hlist.listIterator(); while (li.hasNext()) { Header sipheader = li.next(); retval.add(sipheader.toString()); } return retval; } /** * Get the first element of this list. * * @return SIPHeader first element of the list. */ public Header getFirst() { if (hlist == null || hlist.isEmpty()) return null; else return hlist.get(0); } /** * Get the last element of this list. * * @return SIPHeader last element of the list. */ public Header getLast() { if (hlist == null || hlist.isEmpty()) return null; return hlist.get(hlist.size() - 1); } /** * Get the class for the headers of this list. * * @return Class of header supported by this list. */ public Class<HDR> getMyClass() { return this.myClass; } /** * Empty check * * @return boolean true if list is empty */ public boolean isEmpty() { return hlist.isEmpty(); } /** * Get an initialized iterator for my imbedded list * * @return the generated ListIterator */ public ListIterator<HDR> listIterator() { return hlist.listIterator(0); } /** * Get the imbedded linked list. * * @return the imedded linked list of SIP headers. */ public List<HDR> getHeaderList() { return this.hlist; } /** * Get the list iterator for a given position. * * @param position * position for the list iterator to return * @return the generated list iterator */ public ListIterator<HDR> listIterator(int position) { return hlist.listIterator(position); } /** * Remove the first element of this list. */ public void removeFirst() { if (hlist.size() != 0) hlist.remove(0); } /** * Remove the last element of this list. */ public void removeLast() { if (hlist.size() != 0) hlist.remove(hlist.size() - 1); } /** * Remove a sip header from this list of sip headers. * * @param obj * SIPHeader to remove * @return boolean */ public boolean remove(HDR obj) { if (hlist.size() == 0) return false; else return hlist.remove(obj); } /** * Set the root class for all objects inserted into my list (for assertion * check) * * @param cl * class to set */ protected void setMyClass(Class<HDR> cl) { this.myClass = cl; } /** * convert to a string representation (for printing). * * @param indentation * int to set * @return String string representation of object (for printing). */ public String debugDump(int indentation) { stringRepresentation = ""; String indent = new Indentation(indentation).getIndentation(); String className = this.getClass().getName(); sprint(indent + className); sprint(indent + "{"); for (Iterator<HDR> it = hlist.iterator(); it.hasNext();) { HDR sipHeader = (HDR) it.next(); sprint(indent + sipHeader.debugDump()); } sprint(indent + "}"); return stringRepresentation; } /** * convert to a string representation * * @return String */ public String debugDump() { return debugDump(0); } /** * Array conversion. * * @return SIPHeader [] */ public Object[] toArray() { return hlist.toArray(); } /** * index of an element. * * @return index of the given element (-1) if element does not exist. */ public int indexOf(GenericObject gobj) { return hlist.indexOf(gobj); } /** * insert at a location. * * @param index * location where to add the sipHeader. * @param sipHeader * SIPHeader structure to add. */ public void add(int index, HDR sipHeader) throws IndexOutOfBoundsException { hlist.add(index, sipHeader); } /** * Equality comparison operator. * * @param other * the other object to compare with. true is returned iff the * classes match and list of headers herein is equal to the list * of headers in the target (order of the headers is not * important). */ @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == this) return true; if (other instanceof SIPHeaderList) { SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) other; if (this.hlist == that.hlist) return true; else if (this.hlist == null) return that.hlist == null || that.hlist.size() == 0; return this.hlist.equals(that.hlist); } return false; } /** * Template match against a template. null field in template indicates wild * card match. */ public boolean match(SIPHeaderList<?> template) { if (template == null) return true; if (!this.getClass().equals(template.getClass())) return false; SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) template; if (this.hlist == that.hlist) return true; else if (this.hlist == null) return false; else { for (Iterator<SIPHeader> it = that.hlist.iterator(); it.hasNext();) { SIPHeader sipHeader = (SIPHeader) it.next(); boolean found = false; for (Iterator<HDR> it1 = this.hlist.iterator(); it1.hasNext() && !found;) { SIPHeader sipHeader1 = (SIPHeader) it1.next(); found = sipHeader1.match(sipHeader); } if (!found) return false; } return true; } } /** * make a clone of this header list. * * @return clone of this Header. */ public Object clone() { try { Class<?> clazz = this.getClass(); Constructor<?> cons = clazz.getConstructor((Class[])null); SIPHeaderList<HDR> retval = (SIPHeaderList<HDR>) cons.newInstance((Object[])null); retval.headerName = this.headerName; retval.myClass = this.myClass; return retval.clonehlist(this.hlist); } catch (Exception ex) { throw new RuntimeException("Could not clone!", ex); } } protected final SIPHeaderList<HDR> clonehlist(List<HDR> hlistToClone) { if (hlistToClone != null) { for (Iterator<HDR> it = (Iterator<HDR>) hlistToClone.iterator(); it.hasNext();) { Header h = it.next(); this.hlist.add((HDR)h.clone()); } } return this; } /** * Get the number of headers in the list. */ public int size() { return hlist.size(); } /** * Return true if this is a header list (overrides the base class method * which returns false). * * @return true */ public boolean isHeaderList() { return true; } /** * Encode the body of this header (the stuff that follows headerName). A.K.A * headerValue. This will not give a reasonable result for WWW-Authenticate, * Authorization, Proxy-Authenticate and Proxy-Authorization and hence this * is protected. */ protected String encodeBody() { return encodeBody(new StringBuilder()).toString(); } protected StringBuilder encodeBody(StringBuilder buffer) { ListIterator<HDR> iterator = this.listIterator(); while (true) { SIPHeader sipHeader = (SIPHeader) iterator.next(); if ( sipHeader == this ) throw new RuntimeException ("Unexpected circularity in SipHeaderList"); sipHeader.encodeBody(buffer); // if (body.equals("")) System.out.println("BODY == "); if (iterator.hasNext()) { if (!this.headerName.equals(PrivacyHeader.NAME)) buffer.append(Separators.COMMA); else buffer.append(Separators.SEMICOLON); continue; } else break; } return buffer; } public boolean addAll(Collection<? extends HDR> collection) { return this.hlist.addAll(collection); } public boolean addAll(int index, Collection<? extends HDR> collection) { return this.hlist.addAll(index, collection); } public boolean containsAll(Collection<?> collection) { return this.hlist.containsAll(collection); } public void clear() { this.hlist.clear(); } public boolean contains(Object header) { return this.hlist.contains(header); } /** * Get the object at the specified location. * * @param index -- * location from which to get the object. * */ public HDR get(int index) { return this.hlist.get(index); } /** * Return the index of a given object. * * @param obj -- * object whose index to compute. */ public int indexOf(Object obj) { return this.hlist.indexOf(obj); } /** * Return the iterator to the imbedded list. * * @return iterator to the imbedded list. * */ public java.util.Iterator<HDR> iterator() { return this.hlist.listIterator(); } /** * Get the last index of the given object. * * @param obj -- * object whose index to find. */ public int lastIndexOf(Object obj) { return this.hlist.lastIndexOf(obj); } /** * Remove the given object. * * @param obj -- * object to remove. * */ public boolean remove(Object obj) { return this.hlist.remove(obj); } /** * Remove the object at a given index. * * @param index -- * index at which to remove the object */ public HDR remove(int index) { return this.hlist.remove(index); } /** * Remove all the elements. * @see List#removeAll(java.util.Collection) */ public boolean removeAll(java.util.Collection<?> collection) { return this.hlist.removeAll(collection); } /** * @see List#retainAll(java.util.Collection) * @param collection */ public boolean retainAll(java.util.Collection<?> collection) { return this.hlist.retainAll(collection); } /** * Get a sublist of the list. * * @see List#subList(int, int) */ public java.util.List<HDR> subList(int index1, int index2) { return this.hlist.subList(index1, index2); } /** * @see Object#hashCode() * @return -- the computed hashcode. */ public int hashCode() { return this.headerName.hashCode(); } /** * Set a SIPHeader at a particular position in the list. * * @see List#set(int, java.lang.Object) */ public HDR set(int position, HDR sipHeader) { return hlist.set(position, sipHeader); } public static void setPrettyEncode(boolean flag) { prettyEncode = flag; } public <T> T[] toArray(T[] array) { return this.hlist.toArray(array); } }