Coverage Report - net.wotonomy.datastore.DefaultDataView
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultDataView
0% 
0% 
2.109
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2000 Michael Powers
 4  
 
 5  
 This library is free software; you can redistribute it and/or
 6  
 modify it under the terms of the GNU Lesser General Public
 7  
 License as published by the Free Software Foundation; either
 8  
 version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
 This library is distributed in the hope that it will be useful,
 11  
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 Lesser General Public License for more details.
 14  
 
 15  
 You should have received a copy of the GNU Lesser General Public
 16  
 License along with this library; if not, see http://www.gnu.org
 17  
 */
 18  
 
 19  
 package net.wotonomy.datastore;
 20  
 
 21  
 import java.util.ArrayList;
 22  
 import java.util.Collection;
 23  
 import java.util.Iterator;
 24  
 import java.util.LinkedList;
 25  
 import java.util.List;
 26  
 import java.util.ListIterator;
 27  
 import java.util.Observable;
 28  
 
 29  
 public class DefaultDataView extends Observable 
 30  
         implements DataView
 31  
 {
 32  
     protected DataSoup backingSoup;
 33  
     protected List objectList;
 34  
     protected List keyList;
 35  
     protected List addedObjectList;
 36  
     protected List removedObjectList;
 37  
     protected List addedKeyList;
 38  
     protected List removedKeyList;
 39  
     protected Collection updatedObjects;
 40  
     protected boolean fullyLoaded;
 41  
     
 42  0
         DefaultDataView( DataSoup aSoup, Collection aKeyList )
 43  0
         {
 44  0
                 backingSoup = aSoup;
 45  0
                 objectList = new ArrayList();
 46  0
                 keyList = new ArrayList();
 47  0
                 addedObjectList = new ArrayList();
 48  0
                 removedObjectList = new ArrayList();
 49  0
                 addedKeyList = new ArrayList();
 50  0
                 removedKeyList = new ArrayList();
 51  0
                 updatedObjects = new LinkedList();
 52  0
                 fullyLoaded = false;
 53  
 
 54  0
                 setKeyList( aKeyList );
 55  0
         }
 56  
         
 57  
         void setKeyList( Collection aCollection )
 58  
         {
 59  0
                 fullyLoaded = false;
 60  0
                 addedObjectList.clear();
 61  0
                 removedObjectList.clear();
 62  0
                 addedKeyList.clear();
 63  0
                 removedKeyList.clear();
 64  0
                 updatedObjects.clear();
 65  0
                 keyList.clear();
 66  0
                 objectList.clear();
 67  0
                 if ( ( aCollection == null ) || ( aCollection.size() == 0 ) )
 68  
                 {
 69  0
                         return;
 70  
                 }
 71  0
                 keyList.addAll( aCollection );
 72  0
                 for ( int i = 0; i < keyList.size(); i++ )
 73  
                 {
 74  0
                         objectList.add( null );
 75  
                 }
 76  0
         }
 77  
 
 78  
         public Object get( int i )
 79  
         {
 80  0
                 if ( i > keyList.size() ) return null;
 81  
 
 82  0
                 Object o = objectList.get( i );
 83  0
                 if ( o == null )
 84  
                 {
 85  0
                         Object key = keyList.get( i );
 86  0
                         if ( key == null ) return null; // FIXME!!
 87  
 
 88  
             //NOTE: this is the gateway for getting object from the soup
 89  0
                         o = backingSoup.getObjectByKey( (DataKey) key );
 90  
 
 91  0
                         objectList.set( i, o );
 92  
                 }
 93  0
                 return o;
 94  
         }
 95  
 
 96  
     public int indexOf( Object o )
 97  
     {
 98  0
         if ( o == null ) return -1;
 99  0
         for ( int i = 0; i < size(); i++ )
 100  
         {
 101  0
             if ( o.equals( get( i ) ) )
 102  
             {
 103  0
                 return i;
 104  
             }
 105  
         }
 106  0
         return -1;
 107  
     }
 108  
 
 109  
     private int indexOfIdenticalObject( Object o )
 110  
     {
 111  0
         if ( o == null ) return -1;
 112  0
         for ( int i = 0; i < size(); i++ )
 113  
         {
 114  0
             if ( o == get( i ) )
 115  
             {
 116  0
                 return i;
 117  
             }
 118  
         }
 119  0
         return -1;
 120  
     }
 121  
 
 122  
     public int lastIndexOf( Object o )
 123  
     {
 124  0
         if ( o == null ) return -1;
 125  0
         int lastIndex = -1;
 126  0
         for ( int i = 0; i < size(); i++ )
 127  
         {
 128  0
             if ( o.equals( get( i ) ) )
 129  
             {
 130  0
                 lastIndex = i;
 131  
             }
 132  
         }
 133  0
         return lastIndex;
 134  
     }
 135  
 
 136  
         protected void loadAllObjects()
 137  
         {
 138  0
                 if ( fullyLoaded ) return;
 139  0
                 for ( int i = 0; i < keyList.size(); i++ )
 140  
                 {
 141  0
                         get( i );
 142  
                 }
 143  0
                 fullyLoaded = true;
 144  0
         }
 145  
         
 146  
     // convenience to return the first object, or null.
 147  
     public Object getObject()
 148  
     {
 149  0
             return get( 0 );
 150  
         } 
 151  
         
 152  
         // marked object as updated
 153  
         public void update( Object anObject )
 154  
         {                
 155  0
                 if ( contains( anObject ) )
 156  
                 {
 157  0
                         if ( ! addedObjectList.contains( anObject ) )
 158  
                         {
 159  0
                                 updatedObjects.add( anObject );
 160  
                 }
 161  
                 }
 162  
 
 163  
         // notification
 164  0
         setChanged();
 165  0
         notifyObservers( anObject );
 166  0
         }
 167  
 
 168  
     // DefaultDataViews know their parent soup to perform the query
 169  
         //        and take the subset
 170  
     public DataView query(
 171  0
             String aProperty, Object beginKey, Object endKey ) { return this; }
 172  
 
 173  
         public boolean commit()
 174  
         {
 175  
         int index;
 176  
         Object o;
 177  
         DataKey key;
 178  0
                 for ( int i = 0; i < addedObjectList.size(); i++ )
 179  
                 {
 180  0
             o = addedObjectList.get(i);
 181  0
                         key = backingSoup.addObject( o );
 182  0
             index = indexOfIdenticalObject( o );
 183  0
             keyList.set( index, key );
 184  
                 }
 185  0
                 addedObjectList.clear();
 186  0
                 addedKeyList.clear();
 187  0
                 for ( int i = 0; i < removedObjectList.size(); i++ )
 188  
                 {
 189  0
                     backingSoup.removeObject( (DataKey) removedKeyList.get(i) );
 190  
                 }
 191  0
                 removedObjectList.clear();
 192  0
                 removedKeyList.clear();
 193  
 
 194  
                 int i;
 195  0
                 Iterator it = updatedObjects.iterator();
 196  0
                 while ( it.hasNext() )
 197  
                 {
 198  0
                         i = objectList.indexOf( it.next() );
 199  0
                         backingSoup.updateObject(
 200  0
                                 (DataKey) keyList.get(i), objectList.get(i) );
 201  0
                 }
 202  0
                 updatedObjects.clear();
 203  
 
 204  
         // notification
 205  0
         setChanged();
 206  0
         notifyObservers( this );
 207  
 
 208  0
                 return true;
 209  
         }
 210  
 
 211  
     public DataKey getKeyForObject( Object anObject )
 212  
     {
 213  0
         int index = indexOfIdenticalObject( anObject );
 214  0
         if ( index == -1 ) return null;
 215  0
         return (DataKey) keyList.get( index );
 216  
     }
 217  
 
 218  
     public Object getObjectForKey( DataKey aKey )
 219  
     {
 220  0
         int index = keyList.indexOf( aKey );
 221  0
         if ( index == -1 ) return null;
 222  0
         return get( index );
 223  
     }
 224  
 
 225  
         // interface Collection
 226  
 
 227  0
     public int size () { return keyList.size(); }
 228  0
     public boolean isEmpty () { return keyList.isEmpty(); }
 229  0
     public void clear () { setKeyList( null ); };
 230  0
     public int hashCode() { return keyList.hashCode(); };
 231  
 
 232  
     public boolean equals (Object o)
 233  
     {
 234  0
             if ( ! ( o instanceof DefaultDataView ) ) return false;
 235  0
             return keyList.equals( ((DefaultDataView)o).keyList );
 236  
         }
 237  
 
 238  
     public boolean contains (Object o)
 239  
         {
 240  0
                 loadAllObjects();
 241  0
                 return objectList.contains(o);
 242  
         }
 243  
 
 244  
     public boolean containsAll (Collection c)
 245  
     {
 246  0
             loadAllObjects();
 247  0
             return objectList.containsAll( c );
 248  
     }
 249  
 
 250  
     public boolean add (Object o)
 251  
     {
 252  
             // if previously removed, restore to list
 253  0
             if ( removedObjectList.contains( o ) )
 254  
             {
 255  0
                     int index = removedObjectList.indexOf( o );
 256  0
                     removedObjectList.remove( index );
 257  0
                     Object key = removedKeyList.remove( index );
 258  0
                     objectList.add( o );
 259  0
                     keyList.add( key );
 260  
 
 261  
             // notification
 262  0
             setChanged();
 263  0
             notifyObservers( o );
 264  0
                     return true;
 265  
             }
 266  
 
 267  
             // register and add to lists
 268  0
             Object key = backingSoup.registerTemporaryObject( o );
 269  0
             addedObjectList.add( o );
 270  0
             addedKeyList.add( key );
 271  0
             objectList.add( o );
 272  0
             keyList.add( key );
 273  
 
 274  
         // notification
 275  0
         setChanged();
 276  0
         notifyObservers( o );
 277  0
             return true;
 278  
     }
 279  
 
 280  
     public Object remove( int index )
 281  
     {
 282  0
         Object result = get( index );
 283  0
         if ( remove( result ) )
 284  
         {
 285  0
             return result;
 286  
         }
 287  0
         return null;
 288  
     }
 289  
 
 290  
     public boolean remove (Object o)
 291  
     {
 292  0
             loadAllObjects();
 293  
 
 294  0
             int index = objectList.indexOf( o );
 295  0
             if ( index == -1 ) return false;
 296  
 
 297  0
             objectList.remove( index );
 298  0
             Object key = keyList.remove( index );
 299  
 
 300  0
             if ( updatedObjects.contains( o ) )
 301  
             {
 302  0
                     updatedObjects.remove( o );
 303  
             }
 304  
 
 305  
             // if not previously added, track removal
 306  0
             if ( ! ( removedObjectList.contains( o ) ) )
 307  
             {
 308  0
                     removedObjectList.add( o );
 309  0
                     removedKeyList.add( key );
 310  
             }
 311  
 
 312  
         // notification
 313  0
         setChanged();
 314  0
         notifyObservers( o );
 315  
 
 316  0
             return true;
 317  
     }
 318  
 
 319  
     /**
 320  
     * Set completely replaces the object at the specified
 321  
     * index with the specified object.  The new object is not
 322  
     * marked as inserted, and the old object is not marked
 323  
     * as deleted: the new object will be stored in the soup
 324  
     * with the same key.  The old object is returned.
 325  
     */ 
 326  
     public Object set( int index, Object element )
 327  
     {
 328  0
         Object result = objectList.set( index, element );
 329  0
         update( element );
 330  0
         return result;
 331  
     }
 332  
 
 333  
     public void add( int index, Object o )
 334  
     {
 335  
             // if previously removed, restore to list
 336  0
             if ( removedObjectList.contains( o ) )
 337  
             {
 338  0
                     int i = removedObjectList.indexOf( o );
 339  0
                     removedObjectList.remove( i );
 340  0
                     Object key = removedKeyList.remove( i );
 341  0
                     objectList.add( index, o );
 342  0
                     keyList.add( index, key );
 343  
 
 344  
             // notification
 345  0
             setChanged();
 346  0
             notifyObservers( o );
 347  0
                     return;
 348  
             }
 349  
 
 350  
             // register and add to lists
 351  0
             Object key = backingSoup.registerTemporaryObject( o );
 352  0
             addedObjectList.add( o );
 353  0
             addedKeyList.add( key );
 354  0
             objectList.add( index, o );
 355  0
             keyList.add( index, key );
 356  
 
 357  
         // notification
 358  0
         setChanged();
 359  0
         notifyObservers( o );
 360  0
     }
 361  
 
 362  
     public boolean addAll (Collection c)
 363  
     {
 364  0
             boolean result = true;
 365  0
             Iterator it = c.iterator();
 366  0
             while ( it.hasNext() )
 367  
             {
 368  0
                     result = result && add( it.next() );
 369  0
             }
 370  0
             return result;
 371  
     }
 372  
 
 373  
     public boolean addAll (int index, Collection c)
 374  
     {
 375  0
         int originalSize = size();
 376  0
             boolean result = true;
 377  0
             Iterator it = c.iterator();
 378  0
             while ( it.hasNext() )
 379  
             {
 380  0
                     add( index, it.next() );
 381  0
             }
 382  0
             return ( originalSize + c.size() == size() );
 383  
     }
 384  
 
 385  
     public boolean removeAll (Collection c)
 386  
     {
 387  0
             boolean result = true;
 388  0
             Iterator it = c.iterator();
 389  0
             while ( it.hasNext() )
 390  
             {
 391  0
                     result = result && remove( it.next() );
 392  0
             }
 393  0
             return result;
 394  
     }
 395  
 
 396  
     public boolean retainAll (Collection c)
 397  
     {
 398  0
             removeAll( new ArrayList( objectList ) );
 399  0
             return addAll( c );
 400  
         }
 401  
 
 402  
     public List subList( int fromIndex, int toIndex )
 403  
     {
 404  0
         List result = new LinkedList();
 405  0
         for ( int i = fromIndex; i < toIndex; i++ )
 406  
         {
 407  0
             result.add( get( i ) );
 408  
         }
 409  0
         return result;
 410  
     }
 411  
 
 412  
     public Iterator iterator()
 413  
     {
 414  0
             loadAllObjects();
 415  0
             return objectList.iterator();
 416  
 
 417  
 /*        // uncomment to enable on-demand loading
 418  
                 return new Iterator()
 419  
         {
 420  
                         int index = 0;
 421  
             public boolean hasNext() { return ( index + 1 < keyList.size() ); }
 422  
             public Object next() {
 423  
                             return get( index++ ); }
 424  
             public void remove()
 425  
             {
 426  
                 Object o = get( index );
 427  
                     if ( o != null ) DefaultDataView.this.remove( o );
 428  
             }
 429  
         };
 430  
 */
 431  
     }
 432  
 
 433  
     public ListIterator listIterator()
 434  
     {
 435  0
         return new DataViewIterator( this );
 436  
     }
 437  
 
 438  
     public ListIterator listIterator( int index )
 439  
     {
 440  0
         return new DataViewIterator( this, index );
 441  
     }
 442  
 
 443  
     public Object[] toArray ()
 444  
     {
 445  0
             loadAllObjects();
 446  0
             return objectList.toArray();
 447  
     }
 448  
     public java.lang.Object[] toArray (Object[] array)
 449  
     {
 450  0
             loadAllObjects();
 451  0
             return objectList.toArray( array );
 452  
     }
 453  
 
 454  
     protected class DataViewIterator implements ListIterator
 455  
     {
 456  
         DataView theView;
 457  
         int currentIndex;
 458  
 
 459  
         //TODO: should track current object in addition to index
 460  
         // to track external changes to the view. (or should be listener)
 461  
         Object currentObject;
 462  
 
 463  
         public DataViewIterator( DataView aView )
 464  
         {
 465  0
             this( aView, 0 );
 466  0
         }
 467  
 
 468  0
         public DataViewIterator( DataView aView, int index )
 469  0
         {
 470  0
             theView = aView;
 471  0
             if ( theView.size() > index )
 472  
             {
 473  0
                 currentIndex = index;
 474  0
                 currentObject = theView.get( currentIndex );
 475  0
             }
 476  
             else
 477  
             {
 478  0
                 index = -1;
 479  0
                 currentObject = null;
 480  
             }
 481  0
         }
 482  
 
 483  
         public void add( Object o )
 484  
         {
 485  0
             currentIndex++;
 486  0
             theView.add( currentIndex, o );
 487  0
         }
 488  
 
 489  
         public boolean hasNext()
 490  
         {
 491  0
             return ( theView.size() > currentIndex + 1 );
 492  
         }
 493  
 
 494  
         public boolean hasPrevious()
 495  
         {
 496  0
             return ( currentIndex > -1 );
 497  
         }
 498  
 
 499  
         public Object next()
 500  
         {
 501  0
             return theView.get( ++currentIndex );
 502  
         }
 503  
 
 504  
         public int nextIndex()
 505  
         {
 506  0
             return currentIndex + 1;
 507  
         }
 508  
 
 509  
         public Object previous()
 510  
         {
 511  0
             return theView.get( currentIndex-- );
 512  
         }
 513  
 
 514  
         public int previousIndex()
 515  
         {
 516  0
             return currentIndex;
 517  
         }
 518  
 
 519  
         public void remove()
 520  
         {
 521  0
             theView.remove( currentIndex-- );
 522  0
         }
 523  
 
 524  
         public void set( Object o )
 525  
         {
 526  0
             theView.set( currentIndex, o );
 527  0
         }
 528  
 
 529  
     }
 530  
 }
 531  
 
 532  
 /*
 533  
  * $Log$
 534  
  * Revision 1.2  2006/02/19 16:26:19  cgruber
 535  
  * Move non-unit-test code to tests project
 536  
  * Fix up code to work with proper imports
 537  
  * Fix maven dependencies.
 538  
  *
 539  
  * Revision 1.1  2006/02/16 13:18:56  cgruber
 540  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 541  
  *
 542  
  * Revision 1.2  2001/02/15 21:12:41  mpowers
 543  
  * Added accessors for key throughout the api.  This breaks compatibility.
 544  
  * insertObject now returns the permanent key for the newly created object.
 545  
  * The old way returned a copy of the object which was an additional read
 546  
  * that was often ignored.  Now you can read it only if you need it.
 547  
  * Furthermore, there was not other way of getting the permanent key.
 548  
  *
 549  
  * Revision 1.1.1.1  2000/12/21 15:47:14  mpowers
 550  
  * Contributing wotonomy.
 551  
  *
 552  
  * Revision 1.2  2000/12/20 16:25:36  michael
 553  
  * Added log to all files.
 554  
  *
 555  
  *
 556  
  */
 557