diff --git a/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadService.h b/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadService.h index 3ca714ac9cdd2b0d8bca4b1cfda49c93931b9cc6..1b6903cd9ff351c30026f2800f17bbcb990a9e66 100644 --- a/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadService.h +++ b/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadService.h @@ -63,7 +63,10 @@ id ObjectFromJsonData(NSString *jsonDataString, NSError **error); - (CISDOBAsyncCall *)listNavigationalEntities; //! Get all root-level entities from the openBIS ipad service for the specified navigational entities. This should return all the entities associated with that navigational entity that are considered part of the root set. The success block will be invoked with a collection of CISDOBIpadRawEntity objects. -- (CISDOBAsyncCall *)listRootLevelEntities:(NSArray *)permIds refcons:(NSArray *)refcons; +//- (CISDOBAsyncCall *)listRootLevelEntities:(NSArray *)permIds refcons:(NSArray *)refcons; + +//! Get all root-level entities from the openBIS ipad service for the specified navigational entities. This should return all the entities associated with that navigational entity that are considered part of the root set. Only returns objects that have changed since the date. The success block will be invoked with a collection of CISDOBIpadRawEntity objects. +- (CISDOBAsyncCall *)listChangesSince:(NSDate *)lastUpdateDate rootLevelEntity:(NSArray *)permIds refcons:(NSArray *)refcons; //! Get drill information from the openBIS ipad service -- this will include information about the children of the entity and possibly their children as well. The permIds and refcons collections must have the same cardinality. The success block will be invoked with a collection of CISDOBIpadRawEntity objects. - (CISDOBAsyncCall *)drillOnEntities:(NSArray *)permIds refcons:(NSArray *)refcons; diff --git a/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadService.m b/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadService.m index 622a76cbe37ab8aa9cba5797bef688f151c36d46..7f7b04ce9e4f8591cad7fc5849e1257a9afbe7ce 100644 --- a/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadService.m +++ b/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadService.m @@ -166,7 +166,7 @@ id ObjectFromJsonData(NSString *jsonDataString, NSError **error) CISDOBIpadServiceCall *serviceCall = [self createIpadServiceCallWithParameters: parameters]; return serviceCall; } - +/* - (CISDOBAsyncCall *)listRootLevelEntities:(NSArray *)permIds refcons:(NSArray *)refcons { NSUInteger count = [permIds count]; @@ -182,6 +182,24 @@ id ObjectFromJsonData(NSString *jsonDataString, NSError **error) if (serviceCall.timeoutInterval < 60.) serviceCall.timeoutInterval = 60.; return serviceCall; } +*/ +- (CISDOBAsyncCall *)listChangesSince:(NSDate *)lastUpdateDate rootLevelEntity:(NSArray *)permIds refcons:(NSArray *)refcons +{ + NSUInteger count = [permIds count]; + NSAssert([refcons count] == count, @"Drilling requires permIds and refcons. There must be an equal number of these."); + NSArray *entities; + entities = [self convertToEntitiesPermIds: permIds refcons: refcons count: count]; + NSDictionary *parameters = + [NSDictionary dictionaryWithObjectsAndKeys: + @"ROOT", @"requestKey", + entities, @"entities", + [NSString stringWithFormat: @"%f", [lastUpdateDate timeIntervalSince1970]], @"lastupdate", nil]; + CISDOBIpadServiceCall *serviceCall = [self createIpadServiceCallWithParameters: parameters]; + // Make sure the timeout interval is at least 60s + if (serviceCall.timeoutInterval < 60.) serviceCall.timeoutInterval = 60.; + return serviceCall; + +} - (NSArray *)convertToEntitiesPermIds:(NSArray *)permIds refcons:(NSArray *)refcons count:(NSUInteger)count { diff --git a/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadServiceManager.h b/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadServiceManager.h index 08cca8141558895e37b5066fab174aae5780864d..4334e753dd02d8452ffcf74ab669216d7d430bf1 100644 --- a/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadServiceManager.h +++ b/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadServiceManager.h @@ -71,6 +71,8 @@ typedef void (^AuthenticationChallengeBlock)(CISDOBAsyncCall *call, NSURLAuthent typedef void (^MocSaveBlock)(CISDOBIpadServiceManager *serviceManager, NSArray *deletedEntityPermIds); +typedef void (^MocPostSaveBlock)(CISDOBIpadServiceManager *serviceManager); + /** @@ -90,7 +92,7 @@ typedef void (^MocSaveBlock)(CISDOBIpadServiceManager *serviceManager, NSArray * @property (readonly) NSOperationQueue *queue; @property (readonly) NSString *sessionToken; @property (nonatomic, getter=isOnline) BOOL online; -@property (nonatomic, getter=isSyncDone) BOOL syncDone; +@property (getter=isSyncDone) BOOL syncDone; @property(strong, nonatomic) NSDate *lastRootSetUpdateDate; @@ -100,6 +102,9 @@ typedef void (^MocSaveBlock)(CISDOBIpadServiceManager *serviceManager, NSArray * //! Called before the service manager saves the managed object context which will delete the entities with the deletedEntityPermIds @property (copy, nonatomic) MocSaveBlock mocSaveBlock; +//! Called after the service manager successfully saves the managed object context +@property (copy, nonatomic) MocPostSaveBlock mocPostSaveBlock; + // Initialization - (id)initWithStoreUrl:(NSURL *)storeUrl openbisUrl:(NSURL *)openbisUrl trusted:(BOOL)trusted error:(NSError **)error; diff --git a/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadServiceManager.m b/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadServiceManager.m index fb6b3a3553f5cf661e08206ba8d718a77c457848..cfa3e7b29a528b3dd55b5240bec96f8c5ab74e18 100644 --- a/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadServiceManager.m +++ b/openbis-ipad/source/objc/BisKit/Classes/CISDOBIpadServiceManager.m @@ -164,7 +164,11 @@ static NSManagedObjectContext* GetMainThreadManagedObjectContext(NSURL* storeUrl - (BOOL)saveManagedObjectContextDeleting:(NSArray *)deletedEntities error:(NSError **)error { if (self.mocSaveBlock) self.mocSaveBlock(self, deletedEntities); - return [self.managedObjectContext save: error]; + BOOL success = [self.managedObjectContext save: error]; + if (success) { + if (self.mocPostSaveBlock) self.mocPostSaveBlock(self); + } + return success; } - (void)pruneEntitiesNotifying:(CISDOBIpadServiceManagerCall *)managerCall @@ -319,13 +323,14 @@ static NSManagedObjectContext* GetMainThreadManagedObjectContext(NSURL* storeUrl CISDOBAsyncCall *call = [self.service listNavigationalEntities]; CISDOBIpadServiceManagerCall *managerCall = [[CISDOBIpadServiceManagerCall alloc] initWithServiceManager: self serviceCall: call]; + // Save the update date to be the time the call is constructed (i.e., before the call is made) + NSDate *timeOfCallConstruction = [NSDate date]; __weak CISDOBIpadServiceManager *weakSelf = self; call.success = ^(id result) { weakSelf.online = YES; - // Update the set update date - weakSelf.lastRootSetUpdateDate = [NSDate date]; + self.lastRootSetUpdateDate = timeOfCallConstruction; CISDOBIpadServiceManagerRetrieveRootSetCommand *command = [[CISDOBIpadServiceManagerRetrieveRootSetCommand alloc] init]; command.serviceManager = weakSelf; command.serviceManagerCall = managerCall; @@ -651,12 +656,16 @@ static NSManagedObjectContext* GetMainThreadManagedObjectContext(NSURL* storeUrl NSError *error; // Remove entities that were not updated since the prune cutoff date // Remove all entities that were not mentioned - NSFetchRequest *fetchRequest = [self.serviceManager fetchRequestForEntitiesNotUpdatedSince: self.pruneCutoffDate]; - NSArray *entitiesToDelete = [self.managedObjectContext executeFetchRequest: fetchRequest error: &error]; - for (CISDOBIpadEntity *entity in entitiesToDelete) { - [(NSMutableArray *)_deletedEntityPermIds addObject: entity.permId]; - [self.managedObjectContext deleteObject: entity]; - } + + // TODO Do not pune any more (change still in progress...) +// NSFetchRequest *fetchRequest = [self.serviceManager fetchRequestForEntitiesNotUpdatedSince: self.pruneCutoffDate]; +// NSArray *entitiesToDelete = [self.managedObjectContext executeFetchRequest: fetchRequest error: &error]; +// for (CISDOBIpadEntity *entity in entitiesToDelete) { +// [(NSMutableArray *)_deletedEntityPermIds addObject: entity.permId]; +// [self.managedObjectContext deleteObject: entity]; +// } + + // Could be an issue -- synchDone variable not updated in the main thread self.serviceManager.syncDone = YES; [[NSNotificationCenter defaultCenter] postNotificationName: CISDOBIpadServiceDidSynchPruningEntitiesNotification object: self]; success = [self.managedObjectContext save: &error]; @@ -809,7 +818,7 @@ static NSManagedObjectContext* GetMainThreadManagedObjectContext(NSURL* storeUrl NSArray *permIds = [NSArray arrayWithObject: navEntity.permId]; NSArray *refcons = [NSArray arrayWithObject: navEntity.refcon]; - CISDOBAsyncCall *call = [self.serviceManager.service listRootLevelEntities: permIds refcons: refcons]; + CISDOBAsyncCall *call = [self.serviceManager.service listChangesSince: self.serviceManager.lastRootSetUpdateDate rootLevelEntity: permIds refcons: refcons]; call.success = ^(id result) { [self.serviceManager syncEntities: result notifying: nil]; if (currentIndex+1 == count) { @@ -831,7 +840,7 @@ static NSManagedObjectContext* GetMainThreadManagedObjectContext(NSURL* storeUrl // listRootLevelEntites without arguments NSArray *permIds = [NSArray array]; NSArray *refcons = [NSArray array]; - CISDOBAsyncCall *call = [self.serviceManager.service listRootLevelEntities: permIds refcons: refcons]; + CISDOBAsyncCall *call = [self.serviceManager.service listChangesSince: self.serviceManager.lastRootSetUpdateDate rootLevelEntity: permIds refcons: refcons]; call.success = ^(id result) { [self.serviceManager syncEntities: result notifying: nil]; diff --git a/openbis-ipad/source/objc/BisKit/Classes/persistent-data-model.xcdatamodeld/persistent-data-model.xcdatamodel/contents b/openbis-ipad/source/objc/BisKit/Classes/persistent-data-model.xcdatamodeld/persistent-data-model.xcdatamodel/contents index 4d2005a53413a5693a54856acc51ff99186632c6..faff8ff020eb640f0e7d44bd8a26a017ec81b9fd 100644 --- a/openbis-ipad/source/objc/BisKit/Classes/persistent-data-model.xcdatamodeld/persistent-data-model.xcdatamodel/contents +++ b/openbis-ipad/source/objc/BisKit/Classes/persistent-data-model.xcdatamodeld/persistent-data-model.xcdatamodel/contents @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11G56" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic"> +<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="2057" systemVersion="12D78" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic"> <entity name="CISDOBIpadEntity" representedClassName="CISDOBIpadEntity" syncable="YES"> <attribute name="category" optional="YES" attributeType="String" indexed="YES" syncable="YES"/> <attribute name="childrenPermIds" optional="YES" transient="YES" syncable="YES"/> @@ -22,6 +22,6 @@ <fetchRequest name="EntityAndChildren" entity="CISDOBIpadEntity" predicateString="SELF == $ENTITY OR permId IN $CHILDREN" fetchBatchSize="20"/> <fetchRequest name="RootEntities" entity="CISDOBIpadEntity" predicateString="rootLevel == 0" fetchBatchSize="20"/> <elements> - <element name="CISDOBIpadEntity" positionX="0" positionY="0" width="0" height="0"/> + <element name="CISDOBIpadEntity" positionX="0" positionY="0" width="128" height="270"/> </elements> </model> \ No newline at end of file diff --git a/openbis-ipad/source/objc/openBIS/openBIS.xcodeproj/project.xcworkspace/xcuserdata/juanf.xcuserdatad/UserInterfaceState.xcuserstate b/openbis-ipad/source/objc/openBIS/openBIS.xcodeproj/project.xcworkspace/xcuserdata/juanf.xcuserdatad/UserInterfaceState.xcuserstate index 0fe81a140016828bf27d26df9fa19bcf4b2c51ab..b8286a113b469be908e8cc4a096977a566d8d7be 100644 Binary files a/openbis-ipad/source/objc/openBIS/openBIS.xcodeproj/project.xcworkspace/xcuserdata/juanf.xcuserdatad/UserInterfaceState.xcuserstate and b/openbis-ipad/source/objc/openBIS/openBIS.xcodeproj/project.xcworkspace/xcuserdata/juanf.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/openbis-ipad/source/objc/openBIS/openBIS/CISDOBAppDelegate.m b/openbis-ipad/source/objc/openBIS/openBIS/CISDOBAppDelegate.m index 10e77f1eb6c03b44c140d5995db1cafff06a9bad..e9fcc8a22a46e692a85604a23f54f39d06664a64 100644 --- a/openbis-ipad/source/objc/openBIS/openBIS/CISDOBAppDelegate.m +++ b/openbis-ipad/source/objc/openBIS/openBIS/CISDOBAppDelegate.m @@ -55,6 +55,8 @@ NSURL *StoreUrlFromOpenbisUrl(NSURL *applicationDocumentsDirectory, NSURL *openb - (NSString *)username { return [[NSUserDefaults standardUserDefaults] stringForKey: @"openbis_username"]; } - (NSString *)password { return [[NSUserDefaults standardUserDefaults] stringForKey: @"openbis_password"]; } +- (NSDate *)lastUpdatedDate { return [[NSUserDefaults standardUserDefaults] objectForKey: @"last_updated_date"]; } + - (NSURL *)openbisUrl { NSString *urlString = [[NSUserDefaults standardUserDefaults] stringForKey: @"openbis_server_url"]; return [NSURL URLWithString: urlString]; @@ -68,6 +70,11 @@ NSURL *StoreUrlFromOpenbisUrl(NSURL *applicationDocumentsDirectory, NSURL *openb { return [[NSUserDefaults standardUserDefaults] setObject: password forKey: @"openbis_password"]; } +- (void)setLastUpdatedDate:(NSDate *)lastUpdatedDate +{ + return [[NSUserDefaults standardUserDefaults] setObject: lastUpdatedDate forKey: @"last_updated_date"]; +} + - (void)setOpenbisUrl:(NSURL *)openbisUrl { return [[NSUserDefaults standardUserDefaults] setObject: [openbisUrl absoluteString] forKey: @"openbis_server_url"]; @@ -274,6 +281,10 @@ NSURL *StoreUrlFromOpenbisUrl(NSURL *applicationDocumentsDirectory, NSURL *openb if (!_serviceManager) return NO; } + // Initialize the lastUpdateDate of the service manager from the stored state + NSDate* lastUpdatedDate = [self lastUpdatedDate]; + _serviceManager.lastRootSetUpdateDate = lastUpdatedDate; + // Use a weak reference to self in blocks to avoid retain cycles __weak CISDOBAppDelegate *weakSelf = self; _serviceManager.authenticationChallengeBlock = ^(CISDOBAsyncCall *call, NSURLAuthenticationChallenge *challenge) { @@ -282,6 +293,10 @@ NSURL *StoreUrlFromOpenbisUrl(NSURL *applicationDocumentsDirectory, NSURL *openb _serviceManager.mocSaveBlock = ^(CISDOBIpadServiceManager *serviceManager, NSArray *deletedEntityPermIds) { [weakSelf serviceManager: serviceManager willSaveDeletingEntities: deletedEntityPermIds]; }; + _serviceManager.mocPostSaveBlock = ^(CISDOBIpadServiceManager *serviceManager) { + // Update the lastUpdateDate to the time the service manager was created + [weakSelf setLastUpdatedDate: serviceManager.lastRootSetUpdateDate]; + }; return YES; }