Home | History | Annotate | Download | only in ios
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #if !defined(__has_feature) || !__has_feature(objc_arc)
      6 #error "This file requires ARC support."
      7 #endif
      8 
      9 #import "remoting/ios/data_store.h"
     10 
     11 @interface DataStore (Private)
     12 - (NSString*)itemArchivePath;
     13 @end
     14 
     15 @implementation DataStore {
     16  @private
     17   NSMutableArray* _allHosts;
     18   NSManagedObjectContext* _context;
     19   NSManagedObjectModel* _model;
     20 }
     21 
     22 // Create or Get a static data store
     23 + (DataStore*)sharedStore {
     24   static DataStore* sharedStore = nil;
     25   static dispatch_once_t onceToken;
     26   dispatch_once(&onceToken,
     27                 ^{ sharedStore = [[super allocWithZone:nil] init]; });
     28 
     29   return sharedStore;
     30 }
     31 
     32 // General methods
     33 + (id)allocWithZone:(NSZone*)zone {
     34   return [self sharedStore];
     35 }
     36 
     37 // Load data store from SQLLite backing store
     38 - (id)init {
     39   self = [super init];
     40 
     41   if (self) {
     42     // Read in ChromotingModel.xdatamodeld
     43     _model = [NSManagedObjectModel mergedModelFromBundles:nil];
     44 
     45     NSPersistentStoreCoordinator* psc = [[NSPersistentStoreCoordinator alloc]
     46         initWithManagedObjectModel:_model];
     47 
     48     NSString* path = [self itemArchivePath];
     49     NSURL* storeUrl = [NSURL fileURLWithPath:path];
     50 
     51     NSError* error = nil;
     52 
     53     NSDictionary* tryOptions = @{
     54       NSMigratePersistentStoresAutomaticallyOption : @YES,
     55       NSInferMappingModelAutomaticallyOption : @YES
     56     };
     57     NSDictionary* makeOptions =
     58         @{NSMigratePersistentStoresAutomaticallyOption : @YES};
     59 
     60     if (![psc addPersistentStoreWithType:NSSQLiteStoreType
     61                            configuration:nil
     62                                      URL:storeUrl
     63                                  options:tryOptions
     64                                    error:&error]) {
     65       // An incompatible version of the store exists, delete it and start over
     66       [[NSFileManager defaultManager] removeItemAtURL:storeUrl error:nil];
     67 
     68       [psc addPersistentStoreWithType:NSSQLiteStoreType
     69                         configuration:nil
     70                                   URL:storeUrl
     71                               options:makeOptions
     72                                 error:&error];
     73       [NSException raise:@"Open failed"
     74                   format:@"Reason: %@", [error localizedDescription]];
     75     }
     76 
     77     // Create the managed object context
     78     _context = [[NSManagedObjectContext alloc] init];
     79     [_context setPersistentStoreCoordinator:psc];
     80 
     81     // The managed object context can manage undo, but we don't need it
     82     [_context setUndoManager:nil];
     83 
     84     _allHosts = nil;
     85   }
     86   return self;
     87 }
     88 
     89 // Committing to backing store
     90 - (BOOL)saveChanges {
     91   NSError* err = nil;
     92   BOOL successful = [_context save:&err];
     93   return successful;
     94 }
     95 
     96 // Looking up the backing store path
     97 - (NSString*)itemArchivePath {
     98   NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(
     99       NSDocumentDirectory, NSUserDomainMask, YES);
    100 
    101   // Get one and only document directory from that list
    102   NSString* documentDirectory = [documentDirectories objectAtIndex:0];
    103 
    104   return [documentDirectory stringByAppendingPathComponent:@"store.data"];
    105 }
    106 
    107 // Return an array of all known hosts, if the list hasn't been loaded yet, then
    108 // load it now
    109 - (NSArray*)allHosts {
    110   if (!_allHosts) {
    111     NSFetchRequest* request = [[NSFetchRequest alloc] init];
    112 
    113     NSEntityDescription* e =
    114         [[_model entitiesByName] objectForKey:@"HostPreferences"];
    115 
    116     [request setEntity:e];
    117 
    118     NSError* error;
    119     NSArray* result = [_context executeFetchRequest:request error:&error];
    120     if (!result) {
    121       [NSException raise:@"Fetch failed"
    122                   format:@"Reason: %@", [error localizedDescription]];
    123     }
    124     _allHosts = [result mutableCopy];
    125   }
    126 
    127   return _allHosts;
    128 }
    129 
    130 // Return a HostPreferences if it already exists, otherwise create a new
    131 // HostPreferences to use
    132 - (const HostPreferences*)createHost:(NSString*)hostId {
    133 
    134   const HostPreferences* p = [self getHostForId:hostId];
    135 
    136   if (p == nil) {
    137     p = [NSEntityDescription insertNewObjectForEntityForName:@"HostPreferences"
    138                                       inManagedObjectContext:_context];
    139     p.hostId = hostId;
    140     [_allHosts addObject:p];
    141   }
    142   return p;
    143 }
    144 
    145 - (void)removeHost:(HostPreferences*)p {
    146   [_context deleteObject:p];
    147   [_allHosts removeObjectIdenticalTo:p];
    148 }
    149 
    150 // Search the store for any matching HostPreferences
    151 // return the 1st match or nil
    152 - (const HostPreferences*)getHostForId:(NSString*)hostId {
    153   NSFetchRequest* request = [[NSFetchRequest alloc] init];
    154 
    155   NSEntityDescription* e =
    156       [[_model entitiesByName] objectForKey:@"HostPreferences"];
    157   [request setEntity:e];
    158 
    159   NSPredicate* predicate =
    160       [NSPredicate predicateWithFormat:@"(hostId = %@)", hostId];
    161   [request setPredicate:predicate];
    162 
    163   NSError* error;
    164   NSArray* result = [_context executeFetchRequest:request error:&error];
    165   if (!result) {
    166     [NSException raise:@"Fetch failed"
    167                 format:@"Reason: %@", [error localizedDescription]];
    168   }
    169 
    170   for (HostPreferences* curHost in result) {
    171     return curHost;
    172   }
    173   return nil;
    174 }
    175 
    176 @end
    177