Clover coverage report - gsbase - 2.0.1
Coverage timestamp: Sat Jan 1 2005 12:30:02 EST
file stats: LOC: 619   Methods: 30
NCLOC: 198   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
NotificationList.java 81.2% 71.4% 50% 67.7%
coverage coverage
 1    /*
 2    * Copyright (c) 1998, 2005 Gargoyle Software Inc. All rights reserved.
 3    *
 4    * Redistribution and use in source and binary forms, with or without
 5    * modification, are permitted provided that the following conditions are met:
 6    *
 7    * 1. Redistributions of source code must retain the above copyright notice,
 8    * this list of conditions and the following disclaimer.
 9    * 2. Redistributions in binary form must reproduce the above copyright notice,
 10    * this list of conditions and the following disclaimer in the documentation
 11    * and/or other materials provided with the distribution.
 12    * 3. The end-user documentation included with the redistribution, if any, must
 13    * include the following acknowledgment:
 14    *
 15    * "This product includes software developed by Gargoyle Software Inc.
 16    * (http://www.GargoyleSoftware.com/)."
 17    *
 18    * Alternately, this acknowledgment may appear in the software itself, if
 19    * and wherever such third-party acknowledgments normally appear.
 20    * 4. The name "Gargoyle Software" must not be used to endorse or promote
 21    * products derived from this software without prior written permission.
 22    * For written permission, please contact info@GargoyleSoftware.com.
 23    * 5. Products derived from this software may not be called "GSBase", nor may
 24    * "GSBase" appear in their name, without prior written permission of
 25    * Gargoyle Software Inc.
 26    *
 27    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 28    * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 29    * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
 30    * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 31    * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 32    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 33    * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 34    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 35    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 36    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 37    */
 38    package com.gargoylesoftware.base.collections;
 39   
 40    import com.gargoylesoftware.base.util.DetailedNullPointerException;
 41    import java.util.ArrayList;
 42    import java.util.Collection;
 43    import java.util.Collections;
 44    import java.util.Iterator;
 45    import java.util.List;
 46    import java.util.ListIterator;
 47   
 48    /**
 49    * This is a wrapper for a List object that fires
 50    * {@link com.gargoylesoftware.base.collections.NotificationListEvent}'s
 51    * whenever the list is modified.
 52    *
 53    * @version $Revision: 1.5 $
 54    * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
 55    */
 56    public class NotificationList
 57    implements
 58    List {
 59   
 60    private final List delegate_;
 61   
 62    private final List listenerList_ = new ArrayList();
 63   
 64    /**
 65    * Construct a new NotificationList.
 66    * @param delegate The list that we will delegate requests to.
 67    */
 68  13 public NotificationList( final List delegate ) {
 69  13 delegate_ = delegate;
 70   
 71  13 assertNotNull("delegate", delegate);
 72    }
 73   
 74    /**
 75    * Appends the specified element to the end of this list (optional
 76    * operation). <p>
 77    *
 78    * Lists that support this operation may place limitations on what
 79    * elements may be added to this list. In particular, some
 80    * lists will refuse to add null elements, and others will impose
 81    * restrictions on the type of elements that may be added. List
 82    * classes should clearly specify in their documentation any restrictions
 83    * on what elements may be added.
 84    *
 85    * @param object element to be appended to this list.
 86    * @return <tt>true</tt> (as per the general contract of the
 87    * <tt>Collection.add</tt> method).
 88    *
 89    * @throws UnsupportedOperationException if the <tt>add</tt> method is not
 90    * supported by this list.
 91    */
 92  12 public boolean add( final Object object ) throws UnsupportedOperationException {
 93  12 final int startIndex = delegate_.size();
 94  12 final boolean rc = delegate_.add(object);
 95  12 fireInsert( startIndex, 1 );
 96  12 return rc;
 97    }
 98   
 99    /**
 100    * Inserts the specified element at the specified position in this list
 101    * (optional operation). Shifts the element currently at that position
 102    * (if any) and any subsequent elements to the right (adds one to their
 103    * indices).
 104    *
 105    * @param index index at which the specified element is to be inserted.
 106    * @param element element to be inserted.
 107    *
 108    * @throws UnsupportedOperationException if the <tt>add</tt> method is not
 109    * supported by this list.
 110    */
 111  1 public void add(final int index, final Object element) throws UnsupportedOperationException {
 112  1 delegate_.add(index, element);
 113  1 fireInsert( index, 1 );
 114    }
 115   
 116    /**
 117    * Appends all of the elements in the specified collection to the end of
 118    * this list, in the order that they are returned by the specified
 119    * collection's iterator (optional operation). The behavior of this
 120    * operation is unspecified if the specified collection is modified while
 121    * the operation is in progress. (Note that this will occur if the
 122    * specified collection is this list, and it's nonempty.)
 123    *
 124    * @param collection collection whose elements are to be added to this list.
 125    * @return <tt>true</tt> if this list changed as a result of the call.
 126    *
 127    * @throws UnsupportedOperationException if the <tt>addAll</tt> method is
 128    * not supported by this list.
 129    * @see #add(Object)
 130    */
 131  5 public boolean addAll( final Collection collection ) throws UnsupportedOperationException {
 132  5 assertNotNull("collection", collection);
 133  4 final int startIndex = delegate_.size();
 134  4 final boolean rc = delegate_.addAll(collection);
 135  4 fireInsert( startIndex, collection.size() );
 136  4 return rc;
 137    }
 138   
 139    /**
 140    * Inserts all of the elements in the specified collection into this
 141    * list at the specified position (optional operation). Shifts the
 142    * element currently at that position (if any) and any subsequent
 143    * elements to the right (increases their indices). The new elements
 144    * will appear in this list in the order that they are returned by the
 145    * specified collection's iterator. The behavior of this operation is
 146    * unspecified if the specified collection is modified while the
 147    * operation is in progress. (Note that this will occur if the specified
 148    * collection is this list, and it's nonempty.)
 149    *
 150    * @param index index at which to insert first element from the specified
 151    * collection.
 152    * @param collection elements to be inserted into this list.
 153    * @return <tt>true</tt> if this list changed as a result of the call.
 154    *
 155    * @throws UnsupportedOperationException if the <tt>addAll</tt> method is
 156    * not supported by this list.
 157    */
 158  2 public boolean addAll(int index, final Collection collection) throws UnsupportedOperationException {
 159  2 assertNotNull("collection", collection);
 160   
 161  1 final boolean rc = delegate_.addAll(index, collection);
 162  1 fireInsert( index, collection.size() );
 163  1 return rc;
 164    }
 165   
 166    /**
 167    * Returns the element at the specified position in this list.
 168    *
 169    * @param index index of element to return.
 170    * @return the element at the specified position in this list.
 171    */
 172  22 public Object get(final int index) {
 173  22 return delegate_.get(index);
 174    }
 175   
 176    /**
 177    * Replaces the element at the specified position in this list with the
 178    * specified element (optional operation).
 179    *
 180    * @param index index of element to replace.
 181    * @param element element to be stored at the specified position.
 182    * @return the element previously at the specified position.
 183    *
 184    * @throws UnsupportedOperationException if the <tt>set</tt> method is not
 185    * supported by this list.
 186    */
 187  1 public Object set(final int index, final Object element) throws UnsupportedOperationException {
 188  1 final List oldValues = new ArrayList(1);
 189  1 oldValues.add(delegate_.get(index));
 190   
 191  1 final List newValues = new ArrayList(1);
 192  1 newValues.add(element);
 193   
 194  1 Object rc = delegate_.set(index, element);
 195   
 196  1 fireChanged( index, oldValues, newValues );
 197  1 return rc;
 198    }
 199   
 200    /**
 201    * Removes the element at the specified position in this list (optional
 202    * operation). Shifts any subsequent elements to the left (subtracts one
 203    * from their indices). Returns the element that was removed from the
 204    * list.
 205    *
 206    * @param index the index of the element to removed.
 207    * @return the element previously at the specified position.
 208    *
 209    * @throws UnsupportedOperationException if the <tt>remove</tt> method is
 210    * not supported by this list.
 211    */
 212  1 public Object remove(final int index) throws UnsupportedOperationException {
 213  1 final List objectsRemoved = new ArrayList(1);
 214  1 objectsRemoved.add(delegate_.get(index));
 215   
 216  1 final Object rc = delegate_.remove(index);
 217  1 fireRemove( index, index, objectsRemoved );
 218  1 return rc;
 219    }
 220   
 221    /**
 222    * Removes the first occurrence in this list of the specified element
 223    * (optional operation). If this list does not contain the element, it is
 224    * unchanged. More formally, removes the element with the lowest index i
 225    * such that <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> (if
 226    * such an element exists).
 227    *
 228    * @param object element to be removed from this list, if present.
 229    * @return <tt>true</tt> if this list contained the specified element.
 230    *
 231    * @throws UnsupportedOperationException if the <tt>remove</tt> method is
 232    * not supported by this list.
 233    */
 234  0 public boolean remove( final Object object ) throws UnsupportedOperationException {
 235  0 final List objectsRemoved = new ArrayList(1);
 236  0 objectsRemoved.add(object);
 237   
 238  0 final int index = delegate_.indexOf(object);
 239  0 final boolean rc = delegate_.remove(object);
 240  0 fireRemove( index, index, objectsRemoved );
 241  0 return rc;
 242    }
 243   
 244    /**
 245    * Removes from this list all the elements that are contained in the
 246    * specified collection (optional operation).
 247    *
 248    * <b>Implementation note</b> This is currently unsupported.
 249    *
 250    * @param collection collection that defines which elements will be removed from
 251    * this list.
 252    * @return <tt>true</tt> if this list changed as a result of the call.
 253    *
 254    * @throws UnsupportedOperationException if the <tt>removeAll</tt> method
 255    * is not supported by this list.
 256    *
 257    * @see #remove(Object)
 258    * @see #contains(Object)
 259    */
 260  0 public boolean removeAll( final Collection collection ) throws UnsupportedOperationException {
 261  0 throw new UnsupportedOperationException("Not implemented yet");
 262    //TODO: Implement this.
 263    // return delegate_.removeAll(collection);
 264    }
 265   
 266    /**
 267    * Retains only the elements in this list that are contained in the
 268    * specified collection (optional operation). In other words, removes
 269    * from this list all the elements that are not contained in the specified
 270    * collection.
 271    *
 272    * <b>Implementation note</b> This is currently unsupported.
 273    *
 274    * @param collection collection that defines which elements this set will retain.
 275    *
 276    * @return <tt>true</tt> if this list changed as a result of the call.
 277    *
 278    * @throws UnsupportedOperationException if the <tt>retainAll</tt> method
 279    * is not supported by this list.
 280    *
 281    * @see #remove(Object)
 282    * @see #contains(Object)
 283    */
 284  0 public boolean retainAll( final Collection collection ) throws UnsupportedOperationException {
 285  0 throw new UnsupportedOperationException("Not implemented yet");
 286    //TODO: Implement this.
 287    // return delegate_.retainAll(collection);
 288    }
 289   
 290    /**
 291    * Returns the index in this list of the first occurrence of the specified
 292    * element, or -1 if this list does not contain this element.
 293    * More formally, returns the lowest index <tt>i</tt> such that
 294    * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
 295    * or -1 if there is no such index.
 296    *
 297    * @param object element to search for.
 298    * @return the index in this list of the first occurrence of the specified
 299    * element, or -1 if this list does not contain this element.
 300    */
 301  0 public int indexOf(final Object object) {
 302  0 return delegate_.indexOf(object);
 303    }
 304   
 305    /**
 306    * Returns the index in this list of the last occurrence of the specified
 307    * element, or -1 if this list does not contain this element.
 308    * More formally, returns the highest index <tt>i</tt> such that
 309    * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
 310    * or -1 if there is no such index.
 311    *
 312    * @param object element to search for.
 313    * @return the index in this list of the last occurrence of the specified
 314    * element, or -1 if this list does not contain this element.
 315    */
 316  0 public int lastIndexOf(final Object object) {
 317  0 return delegate_.lastIndexOf(object);
 318    }
 319   
 320    /**
 321    * Returns a list iterator of the elements in this list (in proper
 322    * sequence).
 323    *
 324    * @return a list iterator of the elements in this list (in proper
 325    * sequence).
 326    */
 327  0 public synchronized ListIterator listIterator() {
 328  0 return delegate_.listIterator();
 329    }
 330   
 331    /**
 332    * Returns a list iterator of the elements in this list (in proper
 333    * sequence), starting at the specified position in this list. The
 334    * specified index indicates the first element that would be returned by
 335    * an initial call to the <tt>next</tt> method. An initial call to
 336    * the <tt>previous</tt> method would return the element with the
 337    * specified index minus one.
 338    *
 339    * @param index index of first element to be returned from the
 340    * list iterator (by a call to the <tt>next</tt> method).
 341    * @return a list iterator of the elements in this list (in proper
 342    * sequence), starting at the specified position in this list.
 343    */
 344  0 public ListIterator listIterator(final int index) {
 345  0 return delegate_.listIterator(index);
 346    }
 347   
 348    /**
 349    * Returns a view of the portion of this list between the specified
 350    * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive. (If
 351    * <tt>fromIndex</tt> and <tt>toIndex</tt> are equal, the returned list is
 352    * empty.) The returned list is backed by this list, so changes in the
 353    * returned list are reflected in this list, and vice-versa. The returned
 354    * list supports all of the optional list operations supported by this
 355    * list.<p>
 356    *
 357    * This method eliminates the need for explicit range operations (of
 358    * the sort that commonly exist for arrays). Any operation that expects
 359    * a list can be used as a range operation by passing a subList view
 360    * instead of a whole list. For example, the following idiom
 361    * removes a range of elements from a list:
 362    * <pre>
 363    * list.subList(from, to).clear();
 364    * </pre>
 365    * Similar idioms may be constructed for <tt>indexOf</tt> and
 366    * <tt>lastIndexOf</tt>, and all of the algorithms in the
 367    * <tt>Collections</tt> class can be applied to a subList.<p>
 368    *
 369    * The semantics of this list returned by this method become undefined if
 370    * the backing list (i.e., this list) is <i>structurally modified</i> in
 371    * any way other than via the returned list. (Structural modifications are
 372    * those that change the size of this list, or otherwise perturb it in such
 373    * a fashion that iterations in progress may yield incorrect results.)
 374    *
 375    * @param fromIndex low endpoint (inclusive) of the subList.
 376    * @param toIndex high endpoint (exclusive) of the subList.
 377    * @return a view of the specified range within this list.
 378    */
 379  0 public List subList(final int fromIndex, final int toIndex) {
 380  0 return delegate_.subList(fromIndex, toIndex);
 381    }
 382   
 383    /**
 384    * Returns an iterator over the elements in this list in proper sequence.
 385    *
 386    * @return an iterator over the elements in this list in proper sequence.
 387    */
 388  0 public Iterator iterator() {
 389  0 return delegate_.iterator();
 390    }
 391   
 392    /**
 393    * Returns <tt>true</tt> if this list contains all of the elements of the
 394    * specified collection.
 395    *
 396    * @param collection collection to be checked for containment in this list.
 397    * @return <tt>true</tt> if this list contains all of the elements of the
 398    * specified collection.
 399    *
 400    * @see #contains(Object)
 401    */
 402  0 public boolean containsAll( final Collection collection ) {
 403  0 return delegate_.containsAll(collection);
 404    }
 405   
 406    /**
 407    * Returns <tt>true</tt> if this list contains the specified element.
 408    * More formally, returns <tt>true</tt> if and only if this list contains
 409    * at least one element <tt>e</tt> such that
 410    * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
 411    *
 412    * @param object element whose presence in this list is to be tested.
 413    * @return <tt>true</tt> if this list contains the specified element.
 414    */
 415  0 public boolean contains( final Object object ) {
 416  0 return delegate_.contains(object);
 417    }
 418   
 419    /**
 420    * Removes all of the elements from this list (optional operation). This
 421    * list will be empty after this call returns (unless it throws an
 422    * exception).
 423    *
 424    * @throws UnsupportedOperationException if the <tt>clear</tt> method is
 425    * not supported by this list.
 426    */
 427  0 public void clear() throws UnsupportedOperationException {
 428  0 delegate_.clear();
 429    }
 430   
 431    /**
 432    * Returns <tt>true</tt> if this list contains no elements.
 433    *
 434    * @return <tt>true</tt> if this list contains no elements.
 435    */
 436  0 public boolean isEmpty() {
 437  0 return delegate_.isEmpty();
 438    }
 439   
 440    /**
 441    * Returns the number of elements in this list. If this list contains
 442    * more than <tt>Integer.MAX_VALUE</tt> elements, returns
 443    * <tt>Integer.MAX_VALUE</tt>.
 444    *
 445    * @return the number of elements in this list.
 446    */
 447  5 public int size() {
 448  5 return delegate_.size();
 449    }
 450   
 451    /**
 452    * Returns an array containing all of the elements in this list in proper
 453    * sequence. Obeys the general contract of the
 454    * <tt>List.toArray</tt> method.
 455    *
 456    * @return an array containing all of the elements in this list in proper
 457    * sequence.
 458    * @see List#toArray(Object[])
 459    */
 460  0 public Object[] toArray() {
 461  0 return delegate_.toArray();
 462    }
 463   
 464    /**
 465    * Returns an array containing all of the elements in this list in proper
 466    * sequence; the runtime type of the returned array is that of the
 467    * specified array. Obeys the general contract of the
 468    * <tt>Collection.toArray(Object[])</tt> method.
 469    *
 470    * @param array the array into which the elements of this list are to
 471    * be stored, if it is big enough; otherwise, a new array of the
 472    * same runtime type is allocated for this purpose.
 473    * @return an array containing the elements of this list.
 474    *
 475    * @throws ArrayStoreException if the runtime type of the specified array
 476    * is not a supertype of the runtime type of every element in
 477    * this list.
 478    */
 479  0 public Object[] toArray( Object array[] ) throws ArrayStoreException {
 480  0 return delegate_.toArray(array);
 481    }
 482   
 483    /**
 484    * Add a NotificationListListener.
 485    * @param listener The listener to add.
 486    */
 487  9 public synchronized void addNotificationListListener(
 488    final NotificationListListener listener ) {
 489   
 490  9 assertNotNull("listener", listener);
 491   
 492  8 listenerList_.add( listener );
 493    }
 494   
 495    /**
 496    * Remove a NotificationListListener.
 497    * @param listener The listener to remove.
 498    */
 499  1 public synchronized void removeNotificationListListener(
 500    final NotificationListListener listener ) {
 501   
 502  1 assertNotNull("listener", listener);
 503  0 listenerList_.remove( listener );
 504    }
 505   
 506    /**
 507    * Fire an insert event.
 508    * @param startIndex The first index
 509    * @param insertCount The number of items being inserted
 510    */
 511  18 private synchronized void fireInsert( final int startIndex,
 512    final int insertCount ) {
 513   
 514    // Is there anything to do?
 515  18 if( listenerList_.isEmpty() ) {
 516  2 return;
 517    }
 518   
 519  16 final int endIndex = startIndex + insertCount;
 520  16 final NotificationListEvent event
 521    = new NotificationListEvent( this,
 522    NotificationListEvent.INSERT,
 523    startIndex,
 524    startIndex,
 525    Collections.EMPTY_LIST,
 526    delegate_.subList(startIndex, endIndex) );
 527   
 528  16 final NotificationListListener listeners[]
 529    = new NotificationListListener[listenerList_.size()];
 530  16 listenerList_.toArray( listeners );
 531   
 532  16 int i;
 533  16 for( i=0; i<listeners.length; i++ ) {
 534  16 listeners[i].listElementsAdded(event);
 535    }
 536    }
 537   
 538    /**
 539    * Fire a remove event.
 540    * @param startIndex The first index
 541    * @param endIndex The last index
 542    * @param objectsRemoved A list of all the objects that have been removd.
 543    */
 544  1 private synchronized void fireRemove( final int startIndex,
 545    final int endIndex,
 546    final List objectsRemoved) {
 547   
 548    // Is there anything to do?
 549  1 if( listenerList_.isEmpty() ) {
 550  0 return;
 551    }
 552   
 553  1 final NotificationListEvent event
 554    = new NotificationListEvent( this,
 555    NotificationListEvent.REMOVE,
 556    startIndex,
 557    endIndex,
 558    objectsRemoved,
 559    Collections.EMPTY_LIST);
 560   
 561  1 final NotificationListListener listeners[]
 562    = new NotificationListListener[listenerList_.size()];
 563  1 listenerList_.toArray( listeners );
 564   
 565  1 int i;
 566  1 for( i=0; i<listeners.length; i++ ) {
 567  1 listeners[i].listElementsRemoved(event);
 568    }
 569    }
 570   
 571    /**
 572    * Fire a changed event.
 573    * @param startIndex The first index
 574    * @param oldValues The old values
 575    * @param newValues The new values
 576    */
 577  1 private synchronized void fireChanged( final int startIndex,
 578    final List oldValues,
 579    final List newValues ) {
 580  1 if( oldValues.size() != newValues.size() ) {
 581  0 throw new IllegalArgumentException("Lists must be the same size:"
 582    + " oldValues.size()="
 583    + oldValues.size()
 584    + " newValues.size()="
 585    + newValues.size() );
 586    }
 587   
 588    // Is there anything to do?
 589  1 if( listenerList_.isEmpty() ) {
 590  0 return;
 591    }
 592   
 593  1 final NotificationListEvent event
 594    = new NotificationListEvent( this,
 595    NotificationListEvent.CHANGE,
 596    startIndex,
 597    startIndex,
 598    oldValues,
 599    newValues);
 600   
 601  1 final NotificationListListener listeners[]
 602    = new NotificationListListener[listenerList_.size()];
 603  1 listenerList_.toArray( listeners );
 604   
 605  1 int i;
 606  1 for( i=0; i<listeners.length; i++ ) {
 607  1 listeners[i].listElementsChanged(event);
 608    }
 609   
 610    }
 611   
 612   
 613  30 private void assertNotNull( final String fieldName, final Object object ) {
 614  30 if( object == null ) {
 615  5 throw new DetailedNullPointerException(fieldName);
 616    }
 617    }
 618    }
 619