blob: 30c12e2ca43705915848e14cb359795e96f057af [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.core;
import java.util.*;
import java.io.Serializable;
/**
* Implements a homogenous consistent linked list. All the objects in the linked
* list must derive from the same root class. This is a useful constraint to
* place on our code as this property is invariant.The list is created with the
* superclass which can be specified as either a class name or a Class.
*
* @version 1.2
*
* @author M. Ranganathan <br/>
*
*
*
*/
public abstract class GenericObjectList extends LinkedList<GenericObject> implements
Serializable, Cloneable{
// Useful constants.
protected static final String SEMICOLON = Separators.SEMICOLON;
protected static final String COLON = Separators.COLON;
protected static final String COMMA = Separators.COMMA;
protected static final String SLASH = Separators.SLASH;
protected static final String SP = Separators.SP;
protected static final String EQUALS = Separators.EQUALS;
protected static final String STAR = Separators.STAR;
protected static final String NEWLINE = Separators.NEWLINE;
protected static final String RETURN = Separators.RETURN;
protected static final String LESS_THAN = Separators.LESS_THAN;
protected static final String GREATER_THAN = Separators.GREATER_THAN;
protected static final String AT = Separators.AT;
protected static final String DOT = Separators.DOT;
protected static final String QUESTION = Separators.QUESTION;
protected static final String POUND = Separators.POUND;
protected static final String AND = Separators.AND;
protected static final String LPAREN = Separators.LPAREN;
protected static final String RPAREN = Separators.RPAREN;
protected static final String DOUBLE_QUOTE = Separators.DOUBLE_QUOTE;
protected static final String QUOTE = Separators.QUOTE;
protected static final String HT = Separators.HT;
protected static final String PERCENT = Separators.PERCENT;
protected int indentation;
protected String listName; // For debugging
private ListIterator<? extends GenericObject> myListIterator;
private String stringRep;
protected Class<?> myClass;
protected String separator;
protected String getIndentation() {
char[] chars = new char[indentation];
java.util.Arrays.fill(chars, ' ');
return new String(chars);
}
/**
* Return true if this supports reflection based cloning.
*/
protected static boolean isCloneable(Object obj) {
return obj instanceof Cloneable;
}
public static boolean isMySubclass(Class<?> other) {
return GenericObjectList.class.isAssignableFrom(other);
}
/**
* Makes a deep clone of this list.
*/
public Object clone() {
GenericObjectList retval = (GenericObjectList) super.clone();
for (ListIterator<GenericObject> iter = retval.listIterator(); iter.hasNext();) {
GenericObject obj = (GenericObject) ((GenericObject) iter.next())
.clone();
iter.set(obj);
}
return retval;
}
public void setMyClass(Class cl) {
myClass = cl;
}
protected GenericObjectList() {
super();
listName = null;
stringRep = "";
separator = ";";
}
protected GenericObjectList(String lname) {
this();
listName = lname;
}
/**
* A Constructor which takes a list name and a class name (for assertion
* checking).
*/
protected GenericObjectList(String lname, String classname) {
this(lname);
try {
myClass = Class.forName(classname);
} catch (ClassNotFoundException ex) {
InternalErrorHandler.handleException(ex);
}
}
/**
* A Constructor which takes a list name and a class (for assertion
* checking).
*/
protected GenericObjectList(String lname, Class objclass) {
this(lname);
myClass = objclass;
}
/**
* Traverse the list given a list iterator
*/
protected GenericObject next(ListIterator iterator) {
try {
return (GenericObject) iterator.next();
} catch (NoSuchElementException ex) {
return null;
}
}
/**
* This is the default list iterator.This will not handle nested list
* traversal.
*/
protected GenericObject first() {
myListIterator = this.listIterator(0);
try {
return (GenericObject) myListIterator.next();
} catch (NoSuchElementException ex) {
return null;
}
}
/**
* Fetch the next object from the list based on the default list iterator
*/
protected GenericObject next() {
if (myListIterator == null) {
myListIterator = this.listIterator(0);
}
try {
return (GenericObject) myListIterator.next();
} catch (NoSuchElementException ex) {
myListIterator = null;
return null;
}
}
/**
* Concatenate two compatible header lists, adding the argument to the tail
* end of this list.
*
* @param <var>
* topFlag </var> set to true to add items to top of list
*/
protected void concatenate(GenericObjectList objList) {
concatenate(objList, false);
}
/**
* Concatenate two compatible header lists, adding the argument either to
* the beginning or the tail end of this list. A type check is done before
* concatenation.
*
* @param <var>
* topFlag </var> set to true to add items to top of list else
* add them to the tail end of the list.
*/
protected void concatenate(GenericObjectList objList, boolean topFlag) {
if (!topFlag) {
this.addAll(objList);
} else {
// add given items to the top end of the list.
this.addAll(0, objList);
}
}
/**
* string formatting function.
*/
private void sprint(String s) {
if (s == null) {
stringRep += getIndentation();
stringRep += "<null>\n";
return;
}
if (s.compareTo("}") == 0 || s.compareTo("]") == 0) {
indentation--;
}
stringRep += getIndentation();
stringRep += s;
stringRep += "\n";
if (s.compareTo("{") == 0 || s.compareTo("[") == 0) {
indentation++;
}
}
/**
* Convert this list of headers to a formatted string.
*/
public String debugDump() {
stringRep = "";
Object obj = this.first();
if (obj == null)
return "<null>";
sprint("listName:");
sprint(listName);
sprint("{");
while (obj != null) {
sprint("[");
sprint(((GenericObject) obj).debugDump(this.indentation));
obj = next();
sprint("]");
}
sprint("}");
return stringRep;
}
/**
* Convert this list of headers to a string (for printing) with an
* indentation given.
*/
public String debugDump(int indent) {
int save = indentation;
indentation = indent;
String retval = this.debugDump();
indentation = save;
return retval;
}
public void addFirst(GenericObject objToAdd) {
if (myClass == null) {
myClass = objToAdd.getClass();
} else {
super.addFirst(objToAdd);
}
}
/**
* Do a merge of the GenericObjects contained in this list with the
* GenericObjects in the mergeList. Note that this does an inplace
* modification of the given list. This does an object by object merge of
* the given objects.
*
* @param mergeList
* is the list of Generic objects that we want to do an object by
* object merge with. Note that no new objects are added to this
* list.
*
*/
public void mergeObjects(GenericObjectList mergeList) {
if (mergeList == null)
return;
Iterator it1 = this.listIterator();
Iterator it2 = mergeList.listIterator();
while (it1.hasNext()) {
GenericObject outerObj = (GenericObject) it1.next();
while (it2.hasNext()) {
Object innerObj = it2.next();
outerObj.merge(innerObj);
}
}
}
/**
* Encode the list in semicolon separated form.
*
* @return an encoded string containing the objects in this list.
* @since v1.0
*/
public String encode() {
if (this.isEmpty())
return "";
StringBuffer encoding = new StringBuffer();
ListIterator iterator = this.listIterator();
if (iterator.hasNext()) {
while (true) {
Object obj = iterator.next();
if (obj instanceof GenericObject) {
GenericObject gobj = (GenericObject) obj;
encoding.append(gobj.encode());
} else {
encoding.append(obj.toString());
}
if (iterator.hasNext())
encoding.append(separator);
else
break;
}
}
return encoding.toString();
}
/**
* Alias for the encode function above.
*/
public String toString() {
return this.encode();
}
/**
* Set the separator (for encoding the list)
*
* @since v1.0
* @param sep
* is the new seperator (default is semicolon)
*/
public void setSeparator(String sep) {
separator = sep;
}
/**
* Hash code. We never expect to put this in a hash table so return a constant.
*/
public int hashCode() { return 42; }
/**
* Equality checking predicate.
*
* @param other
* is the object to compare ourselves to.
* @return true if the objects are equal.
*/
public boolean equals(Object other) {
if (other == null ) return false;
if (!this.getClass().equals(other.getClass()))
return false;
GenericObjectList that = (GenericObjectList) other;
if (this.size() != that.size())
return false;
ListIterator myIterator = this.listIterator();
while (myIterator.hasNext()) {
Object myobj = myIterator.next();
ListIterator hisIterator = that.listIterator();
try {
while (true) {
Object hisobj = hisIterator.next();
if (myobj.equals(hisobj))
break;
}
} catch (NoSuchElementException ex) {
return false;
}
}
ListIterator hisIterator = that.listIterator();
while (hisIterator.hasNext()) {
Object hisobj = hisIterator.next();
myIterator = this.listIterator();
try {
while (true) {
Object myobj = myIterator.next();
if (hisobj.equals(myobj))
break;
}
} catch (NoSuchElementException ex) {
return false;
}
}
return true;
}
/**
* Match with a template (return true if we have a superset of the given
* template. This can be used for partial match (template matching of SIP
* objects). Note -- this implementation is not unnecessarily efficient :-)
*
* @param other
* template object to compare against.
*/
public boolean match(Object other) {
if (!this.getClass().equals(other.getClass()))
return false;
GenericObjectList that = (GenericObjectList) other;
ListIterator hisIterator = that.listIterator();
outer: while (hisIterator.hasNext()) {
Object hisobj = hisIterator.next();
Object myobj = null;
ListIterator myIterator = this.listIterator();
while (myIterator.hasNext()) {
myobj = myIterator.next();
if (myobj instanceof GenericObject)
System.out.println("Trying to match = "
+ ((GenericObject) myobj).encode());
if (GenericObject.isMySubclass(myobj.getClass())
&& ((GenericObject) myobj).match(hisobj))
break outer;
else if (GenericObjectList.isMySubclass(myobj.getClass())
&& ((GenericObjectList) myobj).match(hisobj))
break outer;
}
System.out.println(((GenericObject) hisobj).encode());
return false;
}
return true;
}
}