Home | History | Annotate | Download | only in core
      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.core;
     30 
     31 import java.util.*;
     32 import java.io.Serializable;
     33 
     34 /**
     35  * Implements a homogenous consistent linked list. All the objects in the linked
     36  * list must derive from the same root class. This is a useful constraint to
     37  * place on our code as this property is invariant.The list is created with the
     38  * superclass which can be specified as either a class name or a Class.
     39  *
     40  * @version 1.2
     41  *
     42  * @author M. Ranganathan <br/>
     43  *
     44  *
     45  *
     46  */
     47 public abstract class GenericObjectList extends LinkedList<GenericObject> implements
     48         Serializable, Cloneable{
     49     // Useful constants.
     50     protected static final String SEMICOLON = Separators.SEMICOLON;
     51 
     52     protected static final String COLON = Separators.COLON;
     53 
     54     protected static final String COMMA = Separators.COMMA;
     55 
     56     protected static final String SLASH = Separators.SLASH;
     57 
     58     protected static final String SP = Separators.SP;
     59 
     60     protected static final String EQUALS = Separators.EQUALS;
     61 
     62     protected static final String STAR = Separators.STAR;
     63 
     64     protected static final String NEWLINE = Separators.NEWLINE;
     65 
     66     protected static final String RETURN = Separators.RETURN;
     67 
     68     protected static final String LESS_THAN = Separators.LESS_THAN;
     69 
     70     protected static final String GREATER_THAN = Separators.GREATER_THAN;
     71 
     72     protected static final String AT = Separators.AT;
     73 
     74     protected static final String DOT = Separators.DOT;
     75 
     76     protected static final String QUESTION = Separators.QUESTION;
     77 
     78     protected static final String POUND = Separators.POUND;
     79 
     80     protected static final String AND = Separators.AND;
     81 
     82     protected static final String LPAREN = Separators.LPAREN;
     83 
     84     protected static final String RPAREN = Separators.RPAREN;
     85 
     86     protected static final String DOUBLE_QUOTE = Separators.DOUBLE_QUOTE;
     87 
     88     protected static final String QUOTE = Separators.QUOTE;
     89 
     90     protected static final String HT = Separators.HT;
     91 
     92     protected static final String PERCENT = Separators.PERCENT;
     93 
     94     protected int indentation;
     95 
     96     protected String listName; // For debugging
     97 
     98     private ListIterator<? extends GenericObject> myListIterator;
     99 
    100     private String stringRep;
    101 
    102     protected Class<?> myClass;
    103 
    104     protected String separator;
    105 
    106     protected String getIndentation() {
    107         char[] chars = new char[indentation];
    108         java.util.Arrays.fill(chars, ' ');
    109         return new String(chars);
    110     }
    111 
    112     /**
    113      * Return true if this supports reflection based cloning.
    114      */
    115     protected static boolean isCloneable(Object obj) {
    116         return obj instanceof Cloneable;
    117     }
    118 
    119     public static boolean isMySubclass(Class<?> other) {
    120         return GenericObjectList.class.isAssignableFrom(other);
    121 
    122     }
    123 
    124     /**
    125      * Makes a deep clone of this list.
    126      */
    127     public Object clone() {
    128         GenericObjectList retval = (GenericObjectList) super.clone();
    129         for (ListIterator<GenericObject> iter = retval.listIterator(); iter.hasNext();) {
    130             GenericObject obj = (GenericObject) ((GenericObject) iter.next())
    131                     .clone();
    132             iter.set(obj);
    133         }
    134         return retval;
    135     }
    136 
    137 
    138 
    139     public void setMyClass(Class cl) {
    140         myClass = cl;
    141     }
    142 
    143     protected GenericObjectList() {
    144         super();
    145         listName = null;
    146         stringRep = "";
    147         separator = ";";
    148     }
    149 
    150     protected GenericObjectList(String lname) {
    151         this();
    152         listName = lname;
    153     }
    154 
    155     /**
    156      * A Constructor which takes a list name and a class name (for assertion
    157      * checking).
    158      */
    159 
    160     protected GenericObjectList(String lname, String classname) {
    161         this(lname);
    162         try {
    163             myClass = Class.forName(classname);
    164         } catch (ClassNotFoundException ex) {
    165             InternalErrorHandler.handleException(ex);
    166         }
    167 
    168     }
    169 
    170     /**
    171      * A Constructor which takes a list name and a class (for assertion
    172      * checking).
    173      */
    174 
    175     protected GenericObjectList(String lname, Class objclass) {
    176         this(lname);
    177         myClass = objclass;
    178     }
    179 
    180     /**
    181      * Traverse the list given a list iterator
    182      */
    183     protected GenericObject next(ListIterator iterator) {
    184         try {
    185             return (GenericObject) iterator.next();
    186         } catch (NoSuchElementException ex) {
    187             return null;
    188         }
    189     }
    190 
    191     /**
    192      * This is the default list iterator.This will not handle nested list
    193      * traversal.
    194      */
    195     protected GenericObject first() {
    196         myListIterator = this.listIterator(0);
    197         try {
    198             return (GenericObject) myListIterator.next();
    199         } catch (NoSuchElementException ex) {
    200             return null;
    201         }
    202     }
    203 
    204     /**
    205      * Fetch the next object from the list based on the default list iterator
    206      */
    207     protected GenericObject next() {
    208         if (myListIterator == null) {
    209             myListIterator = this.listIterator(0);
    210         }
    211         try {
    212             return (GenericObject) myListIterator.next();
    213         } catch (NoSuchElementException ex) {
    214             myListIterator = null;
    215             return null;
    216         }
    217     }
    218 
    219     /**
    220      * Concatenate two compatible header lists, adding the argument to the tail
    221      * end of this list.
    222      *
    223      * @param 
    224      *            topFlag </var> set to true to add items to top of list
    225      */
    226     protected void concatenate(GenericObjectList objList) {
    227         concatenate(objList, false);
    228     }
    229 
    230     /**
    231      * Concatenate two compatible header lists, adding the argument either to
    232      * the beginning or the tail end of this list. A type check is done before
    233      * concatenation.
    234      *
    235      * @param 
    236      *            topFlag </var> set to true to add items to top of list else
    237      *            add them to the tail end of the list.
    238      */
    239     protected void concatenate(GenericObjectList objList, boolean topFlag) {
    240         if (!topFlag) {
    241             this.addAll(objList);
    242         } else {
    243             // add given items to the top end of the list.
    244             this.addAll(0, objList);
    245         }
    246     }
    247 
    248     /**
    249      * string formatting function.
    250      */
    251 
    252     private void sprint(String s) {
    253         if (s == null) {
    254             stringRep += getIndentation();
    255             stringRep += "<null>\n";
    256             return;
    257         }
    258 
    259         if (s.compareTo("}") == 0 || s.compareTo("]") == 0) {
    260             indentation--;
    261         }
    262         stringRep += getIndentation();
    263         stringRep += s;
    264         stringRep += "\n";
    265         if (s.compareTo("{") == 0 || s.compareTo("[") == 0) {
    266             indentation++;
    267         }
    268     }
    269 
    270     /**
    271      * Convert this list of headers to a formatted string.
    272      */
    273 
    274     public String debugDump() {
    275         stringRep = "";
    276         Object obj = this.first();
    277         if (obj == null)
    278             return "<null>";
    279         sprint("listName:");
    280         sprint(listName);
    281         sprint("{");
    282         while (obj != null) {
    283             sprint("[");
    284             sprint(((GenericObject) obj).debugDump(this.indentation));
    285             obj = next();
    286             sprint("]");
    287         }
    288         sprint("}");
    289         return stringRep;
    290     }
    291 
    292     /**
    293      * Convert this list of headers to a string (for printing) with an
    294      * indentation given.
    295      */
    296 
    297     public String debugDump(int indent) {
    298         int save = indentation;
    299         indentation = indent;
    300         String retval = this.debugDump();
    301         indentation = save;
    302         return retval;
    303     }
    304 
    305     public void addFirst(GenericObject objToAdd) {
    306         if (myClass == null) {
    307             myClass = objToAdd.getClass();
    308         } else {
    309             super.addFirst(objToAdd);
    310         }
    311     }
    312 
    313     /**
    314      * Do a merge of the GenericObjects contained in this list with the
    315      * GenericObjects in the mergeList. Note that this does an inplace
    316      * modification of the given list. This does an object by object merge of
    317      * the given objects.
    318      *
    319      * @param mergeList
    320      *            is the list of Generic objects that we want to do an object by
    321      *            object merge with. Note that no new objects are added to this
    322      *            list.
    323      *
    324      */
    325 
    326     public void mergeObjects(GenericObjectList mergeList) {
    327 
    328         if (mergeList == null)
    329             return;
    330         Iterator it1 = this.listIterator();
    331         Iterator it2 = mergeList.listIterator();
    332         while (it1.hasNext()) {
    333             GenericObject outerObj = (GenericObject) it1.next();
    334             while (it2.hasNext()) {
    335                 Object innerObj = it2.next();
    336                 outerObj.merge(innerObj);
    337             }
    338         }
    339     }
    340 
    341     /**
    342      * Encode the list in semicolon separated form.
    343      *
    344      * @return an encoded string containing the objects in this list.
    345      * @since v1.0
    346      */
    347     public String encode() {
    348         if (this.isEmpty())
    349             return "";
    350         StringBuffer encoding = new StringBuffer();
    351         ListIterator iterator = this.listIterator();
    352         if (iterator.hasNext()) {
    353             while (true) {
    354                 Object obj = iterator.next();
    355                 if (obj instanceof GenericObject) {
    356                     GenericObject gobj = (GenericObject) obj;
    357                     encoding.append(gobj.encode());
    358                 } else {
    359                     encoding.append(obj.toString());
    360                 }
    361                 if (iterator.hasNext())
    362                     encoding.append(separator);
    363                 else
    364                     break;
    365             }
    366         }
    367         return encoding.toString();
    368     }
    369 
    370     /**
    371      * Alias for the encode function above.
    372      */
    373     public String toString() {
    374         return this.encode();
    375     }
    376 
    377     /**
    378      * Set the separator (for encoding the list)
    379      *
    380      * @since v1.0
    381      * @param sep
    382      *            is the new seperator (default is semicolon)
    383      */
    384     public void setSeparator(String sep) {
    385         separator = sep;
    386     }
    387 
    388     /**
    389      * Hash code. We never expect to put this in a hash table so return a constant.
    390      */
    391     public int hashCode() { return 42; }
    392 
    393     /**
    394      * Equality checking predicate.
    395      *
    396      * @param other
    397      *            is the object to compare ourselves to.
    398      * @return true if the objects are equal.
    399      */
    400     public boolean equals(Object other) {
    401         if (other == null ) return false;
    402         if (!this.getClass().equals(other.getClass()))
    403             return false;
    404         GenericObjectList that = (GenericObjectList) other;
    405         if (this.size() != that.size())
    406             return false;
    407         ListIterator myIterator = this.listIterator();
    408         while (myIterator.hasNext()) {
    409             Object myobj = myIterator.next();
    410             ListIterator hisIterator = that.listIterator();
    411             try {
    412                 while (true) {
    413                     Object hisobj = hisIterator.next();
    414                     if (myobj.equals(hisobj))
    415                         break;
    416                 }
    417             } catch (NoSuchElementException ex) {
    418                 return false;
    419             }
    420         }
    421         ListIterator hisIterator = that.listIterator();
    422         while (hisIterator.hasNext()) {
    423             Object hisobj = hisIterator.next();
    424             myIterator = this.listIterator();
    425             try {
    426                 while (true) {
    427                     Object myobj = myIterator.next();
    428                     if (hisobj.equals(myobj))
    429                         break;
    430                 }
    431             } catch (NoSuchElementException ex) {
    432                 return false;
    433             }
    434         }
    435         return true;
    436     }
    437 
    438     /**
    439      * Match with a template (return true if we have a superset of the given
    440      * template. This can be used for partial match (template matching of SIP
    441      * objects). Note -- this implementation is not unnecessarily efficient :-)
    442      *
    443      * @param other
    444      *            template object to compare against.
    445      */
    446 
    447     public boolean match(Object other) {
    448         if (!this.getClass().equals(other.getClass()))
    449             return false;
    450         GenericObjectList that = (GenericObjectList) other;
    451         ListIterator hisIterator = that.listIterator();
    452         outer: while (hisIterator.hasNext()) {
    453             Object hisobj = hisIterator.next();
    454             Object myobj = null;
    455             ListIterator myIterator = this.listIterator();
    456             while (myIterator.hasNext()) {
    457                 myobj = myIterator.next();
    458                 if (myobj instanceof GenericObject)
    459                     System.out.println("Trying to match  = "
    460                             + ((GenericObject) myobj).encode());
    461                 if (GenericObject.isMySubclass(myobj.getClass())
    462                         && ((GenericObject) myobj).match(hisobj))
    463                     break outer;
    464                 else if (GenericObjectList.isMySubclass(myobj.getClass())
    465                         && ((GenericObjectList) myobj).match(hisobj))
    466                     break outer;
    467             }
    468             System.out.println(((GenericObject) hisobj).encode());
    469             return false;
    470         }
    471         return true;
    472     }
    473 }
    474