• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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