blob: d11506ac1fa0a4060f55f56a3450be695e07dbaf [file] [log] [blame]
/*
* 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.15 $ $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 StringBuffer()).toString();
}
public StringBuffer encode(StringBuffer 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 StringBuffer()).toString();
}
protected StringBuffer encodeBody(StringBuffer 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);
}
}