Coverage Report - net.wotonomy.control.EOFetchSpecification
 
Classes in this File Line Coverage Branch Coverage Complexity
EOFetchSpecification
0% 
0% 
1.865
 
 1  
 /*
 2  
 Wotonomy: OpenStep design patterns for pure Java applications.
 3  
 Copyright (C) 2001 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.control;
 20  
 
 21  
 import java.util.Collection;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 
 25  
 import net.wotonomy.foundation.NSArray;
 26  
 import net.wotonomy.foundation.NSDictionary;
 27  
 import net.wotonomy.foundation.NSMutableArray;
 28  
 import net.wotonomy.foundation.NSMutableDictionary;
 29  
 import net.wotonomy.foundation.NSSelector;
 30  
 import net.wotonomy.foundation.internal.WotonomyException;
 31  
 
 32  
 /**
 33  
 * EOFetchSpecification defines the parameters used to request
 34  
 * objects from an EOObjectStore.  They are commonly created
 35  
 * and passed to a EODataSource which fetches from its
 36  
 * EOEditingContext, which passes the call up to its root 
 37  
 * EOObjectStore's objectsWithFetchSpecification method.
 38  
 *
 39  
 * @author michael@mpowers.net
 40  
 * @author $Author: cgruber $
 41  
 * @version $Revision: 894 $
 42  
 */
 43  
 public class EOFetchSpecification implements EOKeyValueArchiving {
 44  
     private boolean fetchesRawRows;
 45  
     private String entityName;
 46  
     private NSDictionary hints;
 47  
     private boolean deep;
 48  
     private int fetchLimit;
 49  
     private boolean locksObjects;
 50  
     private NSArray prefetchingRelationshipKeyPaths;
 51  
     private boolean promptsAfterFetchLimit;
 52  
     private EOQualifier qualifier;
 53  
     private NSArray rawRowKeyPaths;
 54  
     private boolean refreshesRefetchedObjects;
 55  
     private boolean requiresAllQualifierBindingVariables;
 56  
     private NSArray sortOrderings;
 57  
     private boolean distinct;
 58  
 
 59  
     /**
 60  
     * Default constructor initializes internal state.
 61  
     */ 
 62  0
     public EOFetchSpecification()
 63  0
     {
 64  0
         fetchesRawRows = false;
 65  0
         entityName = null;
 66  0
         hints = null;
 67  0
         deep = true;
 68  0
         fetchLimit = 0;
 69  0
         locksObjects = false;
 70  0
         prefetchingRelationshipKeyPaths = null;
 71  0
         promptsAfterFetchLimit = false;
 72  0
         qualifier = null;
 73  0
         rawRowKeyPaths = null;
 74  0
         refreshesRefetchedObjects = false;
 75  0
         requiresAllQualifierBindingVariables = false;
 76  0
         sortOrderings = null;
 77  0
         distinct = false;
 78  0
     }
 79  
 
 80  
     /**
 81  
     * Constructs a fetch specification for the specified entity type using
 82  
     * the specified qualifier and sort ordering.
 83  
     */
 84  
     public EOFetchSpecification( String anEntityName, EOQualifier aQualifier, List aSortOrderingList )
 85  
     {
 86  0
         this();
 87  0
         entityName = anEntityName;
 88  0
         qualifier = aQualifier;
 89  0
         sortOrderings = new NSArray( (Collection) aSortOrderingList );
 90  0
     }
 91  
     
 92  
     /** 
 93  
     * Constructs a fetch specification for the specified entity type using
 94  
     * the specified qualifier and sort ordering, distinct flag, deep flag,
 95  
     * and hints dictionary.
 96  
     */
 97  
     public EOFetchSpecification( String anEntityName, EOQualifier aQualifier, NSArray aSortOrderingList, 
 98  
         boolean usesDistinct, boolean isDeep, Map aHintMap)
 99  
     {
 100  0
         this();
 101  0
         entityName = anEntityName;
 102  0
         qualifier = aQualifier;
 103  0
         sortOrderings = new NSArray( (Collection) aSortOrderingList );
 104  0
         distinct = usesDistinct;
 105  0
         deep = isDeep;
 106  0
         hints = new NSMutableDictionary( (Map) aHintMap );
 107  0
     }
 108  
 
 109  
     /**
 110  
     * Convenience to return the named fetch specification from the class description
 111  
     * corresponding to the specified entity name.  Returns null if either entityName
 112  
     * or spec name cannot be resolved.
 113  
     */
 114  
     public static EOFetchSpecification fetchSpecificationNamed( String name, String entityName)
 115  
     {
 116  0
         EOClassDescription classDesc = EOClassDescription.classDescriptionForEntityName( entityName );
 117  0
         if ( classDesc == null ) return null;
 118  0
         return classDesc.fetchSpecificationNamed( name );
 119  
     }
 120  
 
 121  
     /**
 122  
     * Implemented to return a new fetch specification that is a deep copy of this one.
 123  
     */
 124  
     public Object clone()
 125  
     {
 126  0
         EOFetchSpecification clone = new EOFetchSpecification();
 127  
     
 128  0
         clone.fetchesRawRows = this.fetchesRawRows;
 129  0
         clone.entityName = this.entityName;
 130  0
         if ( this.hints != null )
 131  0
             clone.hints = new NSDictionary( (Map) this.hints );
 132  0
         clone.deep = this.deep;
 133  0
         clone.locksObjects = this.locksObjects;
 134  0
         if ( this.prefetchingRelationshipKeyPaths != null )
 135  0
             clone.prefetchingRelationshipKeyPaths = 
 136  0
                 new NSArray( (List) prefetchingRelationshipKeyPaths );
 137  0
         clone.promptsAfterFetchLimit = this.promptsAfterFetchLimit;
 138  0
         if ( this.qualifier != null )
 139  0
             clone.qualifier = this.qualifier; //FIXME: probably should clone?
 140  0
         if ( this.rawRowKeyPaths != null )
 141  0
             clone.rawRowKeyPaths = new NSArray( (List) this.rawRowKeyPaths );
 142  0
         clone.refreshesRefetchedObjects = this.refreshesRefetchedObjects;
 143  0
         clone.requiresAllQualifierBindingVariables = 
 144  0
             this.requiresAllQualifierBindingVariables;
 145  0
         if ( this.sortOrderings != null )
 146  0
             clone.sortOrderings = new NSArray( (List) this.sortOrderings );
 147  0
         clone.distinct = this.distinct;
 148  
         
 149  0
         return clone;
 150  
     }
 151  
 
 152  
     /**
 153  
     * Returns the name of the entity fetched by this fetch spec.
 154  
     */
 155  
     public String entityName()
 156  
     {
 157  0
         return entityName;
 158  
     }
 159  
 
 160  
     /**
 161  
     * Returns the current fetch limit.  
 162  
     * A fetch limit of zero indicates no fetch limit.
 163  
     * Zero is the default.
 164  
     */
 165  
     public int fetchLimit()
 166  
     {
 167  0
         return fetchLimit;
 168  
     }
 169  
     
 170  
     /**
 171  
     * Returns whether this fetch spec will fetch raw rows.
 172  
     * Default is false.
 173  
     */
 174  
     public boolean fetchesRawRows()
 175  
     {
 176  0
         return fetchesRawRows;
 177  
     }
 178  
 
 179  
     /**
 180  
     * Returns a fetch specification that resolves the bindings
 181  
     * in the specified map.
 182  
     */
 183  
     public EOFetchSpecification 
 184  
         fetchSpecificationWithQualifierBindings(Map aBindingMap)
 185  
     {
 186  0
         throw new WotonomyException( "Not implemented yet" );
 187  
     }
 188  
 
 189  
     /**
 190  
     * Returns a Map containing the hints used by this fetch specification,
 191  
     * or null if no hints have been specified.
 192  
     */
 193  
     public NSDictionary hints()
 194  
     {
 195  0
         if ( hints == null ) return null;
 196  0
         return new NSDictionary( (NSDictionary) hints );
 197  
     }
 198  
 
 199  
     /**
 200  
     * Returns whether entities related to the primary
 201  
     * entities are fetched by this fetch spec.  If true, all relationships 
 202  
     * whose destinations meet the qualifier criteria will be returned
 203  
     * in addition to primary results.  If false, only the primary entities
 204  
     * will be returned.  Default is true.
 205  
     */ 
 206  
     public boolean isDeep()
 207  
     {
 208  0
         return deep;
 209  
     }
 210  
 
 211  
     /**
 212  
     * Returns whether this data source should lock objects that
 213  
     * are fetched.  Default is false.
 214  
     */
 215  
     public boolean locksObjects()
 216  
     {        
 217  0
         return locksObjects;
 218  
     }
 219  
 
 220  
     /***
 221  
     * Returns a List of relationships for the fetched objects that 
 222  
     * should also be fetched, or null if no such list has been specified.
 223  
     * Use this to avoid additional calls to the server to fetch
 224  
     * relationships that you know you will use.
 225  
     * NOTE: wotonomy allows you to specify non-relational keys
 226  
     * as well.
 227  
     */
 228  
     public NSArray prefetchingRelationshipKeyPaths()
 229  
     {
 230  0
         return prefetchingRelationshipKeyPaths;
 231  
     }
 232  
 
 233  
     /**
 234  
     * Returns whether the user should be prompted to continue
 235  
     * when the fetch limit has been exceeded.  
 236  
     * Default is false.
 237  
     */
 238  
     public boolean promptsAfterFetchLimit()
 239  
     {
 240  0
         return promptsAfterFetchLimit;
 241  
     }
 242  
 
 243  
     /**
 244  
     * Returns the qualifier used by this fetch specification,
 245  
     * or null if none has been specified.
 246  
     */
 247  
     public EOQualifier qualifier()
 248  
     {
 249  0
         return qualifier;
 250  
     }
 251  
 
 252  
     /**
 253  
     * Returns a List of keys or key paths for which
 254  
     * values should be returned when fetching raw rows,
 255  
     * or null if no raw row key paths have been specified.
 256  
     */
 257  
     public NSArray rawRowKeyPaths()
 258  
     {
 259  0
         return rawRowKeyPaths;
 260  
     }
 261  
 
 262  
     /**
 263  
     * Returns whether fetched objects should replace 
 264  
     * modified versions already fetched into an editing context.
 265  
     * If true, those changes will be lost.  
 266  
     * Default is false.
 267  
     */
 268  
     public boolean refreshesRefetchedObjects()
 269  
     {
 270  0
         return refreshesRefetchedObjects;
 271  
     }
 272  
 
 273  
     /**
 274  
     * Returns whether all qualifier bindings must be specified
 275  
     * in order to fetch.  If true, an exception is thrown if 
 276  
     * unspecified bindings exist.  If false, unspecified bindings
 277  
     * will be removed from the qualifier.  Default is false.
 278  
     */
 279  
     public boolean requiresAllQualifierBindingVariables()
 280  
     {
 281  0
         return requiresAllQualifierBindingVariables;
 282  
     }
 283  
 
 284  
     /**
 285  
     * Sets the name of the entity fetched by this spec.
 286  
     */
 287  
     public void setEntityName(String aName)
 288  
     {
 289  0
         entityName = aName;
 290  0
     }
 291  
 
 292  
     /**
 293  
     * Sets whether this fetch spec will return raw rows.
 294  
     */    
 295  
     public void setFetchesRawRows(boolean shouldFetchRawRows)
 296  
     {
 297  0
         fetchesRawRows = shouldFetchRawRows;
 298  0
     }
 299  
 
 300  
     /**
 301  
     * Sets the limit on the number of records returned for this fetch spec.  
 302  
     * Zero indicates no limit on fetches.
 303  
     */
 304  
     public void setFetchLimit(int aLimit)
 305  
     {
 306  0
         fetchLimit = aLimit;
 307  0
     }
 308  
 
 309  
     /**
 310  
     * Sets the hints passed by this fetch spec.
 311  
     */
 312  
     public void setHints(Map aHintMap)
 313  
     {
 314  0
         if ( aHintMap == null )
 315  
         {
 316  0
             hints = null;
 317  0
         }
 318  
         else
 319  
         {
 320  0
             hints = new NSDictionary( (Map) aHintMap );
 321  
         }
 322  0
     }
 323  
 
 324  
     /**
 325  
     * Sets whether this fetch specification fetches deeply.
 326  
     */
 327  
     public void setIsDeep(boolean isDeep)
 328  
     {
 329  0
         deep = isDeep;
 330  0
     }
 331  
 
 332  
     /**
 333  
     * Sets whether this fetch spec locks objects that 
 334  
     * are returned by the fetch.
 335  
     */
 336  
     public void setLocksObjects(boolean shouldLockObjects)
 337  
     {
 338  0
         locksObjects = shouldLockObjects;
 339  0
     }
 340  
 
 341  
     /**
 342  
     * Sets the prefetch key paths that should be used as an optimization
 343  
     * hint to the server.  NOTE: wotonomy allows you to specify non-relationship
 344  
     * keys as well.
 345  
     */
 346  
     public void setPrefetchingRelationshipKeyPaths(List aKeyPathList)
 347  
     {
 348  0
         if ( aKeyPathList == null )
 349  
         {
 350  0
             prefetchingRelationshipKeyPaths = null;
 351  0
         }
 352  
         else
 353  
         {
 354  0
             prefetchingRelationshipKeyPaths = new NSArray( (List) aKeyPathList );
 355  
         }
 356  0
     }
 357  
 
 358  
     /**
 359  
     * Sets whether the user should be prompted when the fetch limit has been
 360  
     * reached.
 361  
     */
 362  
     public void setPromptsAfterFetchLimit(boolean shouldPrompt)
 363  
     {
 364  0
         promptsAfterFetchLimit = shouldPrompt;
 365  0
     }
 366  
 
 367  
     /**
 368  
     * Sets the qualifier used by this fetch specification.
 369  
     */
 370  
     public void setQualifier(EOQualifier aQualifier)
 371  
     {
 372  0
         qualifier = aQualifier;
 373  0
     }
 374  
 
 375  
     /**
 376  
     * Sets the key paths to be returned if this fetch spec
 377  
     * is returning raw rows.
 378  
     */
 379  
     public void setRawRowKeyPaths(List aKeyPathList)
 380  
     {
 381  0
         if ( aKeyPathList == null )
 382  
         {
 383  0
             rawRowKeyPaths = null;
 384  0
         }
 385  
         else
 386  
         {
 387  0
             rawRowKeyPaths = new NSArray( (List) aKeyPathList );
 388  
         }
 389  0
     }
 390  
 
 391  
     /**
 392  
     * Sets whether modified objects in an editing context should 
 393  
     * be replaced by newer versions returned by this fetch spec.
 394  
     */
 395  
     public void setRefreshesRefetchedObjects(boolean shouldRefresh)
 396  
     {
 397  0
         refreshesRefetchedObjects = shouldRefresh;
 398  0
     }
 399  
 
 400  
     /**
 401  
     * Sets whether this fetch spec should require all bindings to be
 402  
     * resolved before executing.
 403  
     */
 404  
     public void setRequiresAllQualifierBindingVariables(boolean shouldRequireAll)
 405  
     {
 406  0
         requiresAllQualifierBindingVariables = shouldRequireAll;
 407  0
     }
 408  
 
 409  
     /**
 410  
     * Sets the sort orderings used by this fetch spec.
 411  
     */
 412  
     public void setSortOrderings(List aSortList)
 413  
     {
 414  0
         if ( aSortList == null ) 
 415  
         {
 416  0
             sortOrderings = null;
 417  0
         }
 418  
         else
 419  
         {
 420  0
             sortOrderings = new NSArray( (List) aSortList );
 421  
         }
 422  0
     }
 423  
 
 424  
     /**
 425  
     * Sets whether this fetch spec should return only distinct
 426  
     * objects.  
 427  
     */
 428  
     public void setUsesDistinct(boolean shouldUseDistinct)
 429  
     {
 430  0
         distinct = shouldUseDistinct;
 431  0
     }
 432  
 
 433  
     /**
 434  
     * Returns a List of the sort orderings used by this fetch spec,
 435  
     * or null if none have been specified.
 436  
     */
 437  
     public NSArray sortOrderings()
 438  
     {
 439  0
         return sortOrderings;
 440  
     }
 441  
 
 442  
     /**
 443  
     * Returns a string representation of this fetch specification.
 444  
     */
 445  
     public String toString()
 446  
     {
 447  0
         return "[FetchSpecification:qualifier=("+qualifier+"),sortOrderings="+sortOrderings+"]";
 448  
     }
 449  
 
 450  
     /**
 451  
     * Returns whether this fetch specification will return only one
 452  
     * reference to each distinct object returned by the fetch.
 453  
     * Default is false.
 454  
     */
 455  
     public boolean usesDistinct()
 456  
     {
 457  0
         return distinct;
 458  
     }
 459  
 
 460  
         public void encodeWithKeyValueArchiver(EOKeyValueArchiver arch) {
 461  0
                 arch.encodeObject("EOFetchSpecification", "class");
 462  0
                 arch.encodeObject(entityName(), "entityName");
 463  0
                 arch.encodeInt(fetchLimit(), "fetchLimit");
 464  
 
 465  
                 //flags
 466  0
                 if (isDeep())
 467  0
                         arch.encodeObject("YES", "isDeep");
 468  0
                 arch.encodeObject(qualifier(), "qualifier");
 469  0
                 if (refreshesRefetchedObjects())
 470  0
                         arch.encodeObject("YES", "refreshesRefetchedObjects");
 471  0
                 if (locksObjects())
 472  0
                         arch.encodeObject("YES", "locksObjects");
 473  0
                 if (fetchesRawRows())
 474  0
                         arch.encodeObject("YES", "fetchesRawRows");
 475  0
                 if (promptsAfterFetchLimit())
 476  0
                         arch.encodeObject("YES", "promptsAfterFetchLimit");
 477  0
                 if (requiresAllQualifierBindingVariables())
 478  0
                         arch.encodeObject("YES", "requiresAllQualifierBindingVariables");
 479  0
                 if (usesDistinct())
 480  0
                         arch.encodeObject("YES", "usesDistinct");
 481  
 
 482  
                 //encode arrays
 483  0
                 if  (sortOrderings() != null) {
 484  0
                         NSMutableArray arr = new NSMutableArray(sortOrderings().count());
 485  0
                         for (int i = 0; i < sortOrderings.count(); i++) {
 486  0
                                 EOSortOrdering so = (EOSortOrdering)sortOrderings().objectAtIndex(i);
 487  0
                                 EOKeyValueArchiver ar2 = new EOKeyValueArchiver();
 488  0
                                 so.encodeWithKeyValueArchiver(ar2);
 489  0
                                 arr.addObject(ar2.dictionary());
 490  
                         }
 491  0
                         arch.encodeObject(arr, "sortOrderings");
 492  
                 }
 493  0
                 if (rawRowKeyPaths != null && rawRowKeyPaths.count() > 0)
 494  0
                         arch.encodeObject(rawRowKeyPaths, "rawRowKeyPaths");
 495  0
                 if (prefetchingRelationshipKeyPaths != null && prefetchingRelationshipKeyPaths.count() > 0)
 496  0
                         arch.encodeObject(rawRowKeyPaths, "prefetchingRelationshipKeyPaths");
 497  0
                 if (hints != null && hints.count() > 0)
 498  0
                         arch.encodeObject(hints, "hints");
 499  0
         }
 500  
 
 501  
         public static Object decodeWithKeyValueUnarchiver(EOKeyValueUnarchiver unarch) {
 502  0
                 EOFetchSpecification fs = new EOFetchSpecification();
 503  0
                 fs.setEntityName((String)unarch.decodeObjectForKey("entityName"));
 504  0
                 fs.setFetchLimit(unarch.decodeIntForKey("fetchLimit"));
 505  0
                 fs.setIsDeep(unarch.decodeBoolForKey("isDeep"));
 506  0
                 fs.setRefreshesRefetchedObjects(unarch.decodeBoolForKey("refreshesRefetchedObjects"));
 507  
 
 508  
                 //Sort orderings
 509  0
                 NSArray arr = (NSArray)unarch.decodeObjectForKey("sortOrderings");
 510  0
                 if  (arr != null && arr.count() > 0) {
 511  0
                         NSMutableArray orderings = new NSMutableArray(arr.count());
 512  0
                         for (int i = 0; i < arr.count(); i++) {
 513  0
                                 NSDictionary so = (NSDictionary)arr.objectAtIndex(i);
 514  0
                                 String selname = (String)so.objectForKey("selectorName");
 515  0
                                 NSSelector selector = EOSortOrdering.CompareAscending;
 516  0
                                 if (selname.startsWith("compareDescending"))
 517  0
                                         selector = EOSortOrdering.CompareDescending;
 518  0
                                 else if (selname.startsWith("compareCaseInsensitiveAscending"))
 519  0
                                         selector = EOSortOrdering.CompareCaseInsensitiveAscending;
 520  0
                                 else if (selname.startsWith("compareCaseInsensitiveDescending"))
 521  0
                                         selector = EOSortOrdering.CompareCaseInsensitiveDescending;
 522  0
                                 EOSortOrdering eoso = new EOSortOrdering((String)so.objectForKey("key"), selector);
 523  0
                                 orderings.addObject(eoso);
 524  
                         }
 525  0
                         fs.setSortOrderings(orderings);
 526  
                 }
 527  
                 //raw rows
 528  0
                 arr = (NSArray)unarch.decodeObjectForKey("rawRowKeyPaths");
 529  0
                 if (arr != null && arr.count() > 0) {
 530  0
                         fs.setFetchesRawRows(true);
 531  0
                         fs.setRawRowKeyPaths(arr);
 532  
                 }
 533  
                 //qualifier
 534  0
                 fs.setQualifier((EOQualifier)unarch.decodeObjectForKey("qualifier"));
 535  0
                 return fs;
 536  
         }
 537  
 
 538  
 }
 539  
 
 540  
 /*
 541  
  * $Log$
 542  
  * Revision 1.2  2006/02/16 16:47:14  cgruber
 543  
  * Move some classes in to "internal" packages and re-work imports, etc.
 544  
  *
 545  
  * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
 546  
  *
 547  
  * Revision 1.1  2006/02/16 13:19:57  cgruber
 548  
  * Check in all sources in eclipse-friendly maven-enabled packages.
 549  
  *
 550  
  * Revision 1.4  2003/08/11 18:19:01  chochos
 551  
  * encoding/decoding with EOKeyValueArchiving now works properly
 552  
  *
 553  
  * Revision 1.3  2003/08/09 01:22:20  chochos
 554  
  * implements EOKeyValueArchiving (and unarchiving)
 555  
  *
 556  
  * Revision 1.2  2001/11/24 17:32:57  mpowers
 557  
  * We now have a real implementation.
 558  
  *
 559  
  * Revision 1.1  2001/02/05 03:45:37  mpowers
 560  
  * Starting work on EOEditingContext.
 561  
  *
 562  
  *
 563  
  */
 564  
     
 565