/ CoreData / NSPersistentStoreCoordinator.m
NSPersistentStoreCoordinator.m
  1  /* Copyright (c)2008 Dan Knapp
  2  
  3  Permission is hereby granted, free of charge, to any person obtaining a copy of
  4  this software and associated documentation files (the "Software"), to deal in
  5  the Software without restriction, including without limitation the rights to
  6  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  7  the Software, and to permit persons to whom the Software is furnished to do so,
  8  subject to the following conditions:
  9  
 10  The above copyright notice and this permission notice shall be included in all
 11  copies or substantial portions of the Software.
 12  
 13  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 14  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 15  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 16  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 17  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 18  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
 19  #import "NSInMemoryPersistentStore.h"
 20  #import "NSManagedObjectID-Private.h"
 21  #import "NSXMLPersistentStore.h"
 22  #import <CoreData/NSManagedObject.h>
 23  #import <CoreData/NSManagedObjectModel.h>
 24  #import <CoreData/NSPersistentStoreCoordinator.h>
 25  #import <Foundation/NSRaise.h>
 26  
 27  NSString *const NSStoreTypeKey = @"NSStoreTypeKey";
 28  NSString *const NSStoreUUIDKey = @"NSStoreUUIDKey";
 29  
 30  NSString *const NSXMLStoreType = @"XML";
 31  NSString *const NSInMemoryStoreType = @"Memory";
 32  NSString *const NSSQLiteStoreType = @"SQLite";
 33  NSString *const NSBinaryStoreType = @"Binary";
 34  NSString *const NSMigratePersistentStoresAutomaticallyOption =
 35          @"NSMigratePersistentStoresAutomaticallyOption";
 36  
 37  NSString *const NSPersistentStoreCoordinatorStoresDidChangeNotification =
 38          @"NSPersistentStoreCoordinatorStoresDidChangeNotification";
 39  NSString *const NSAddedPersistentStoresKey = @"NSAddedPersistentStoresKey";
 40  NSString *const NSRemovedPersistentStoresKey = @"NSRemovedPersistentStoresKey";
 41  NSString *const NSUUIDChangedPersistentStoresKey =
 42          @"NSUUIDChangedPersistentStoresKey";
 43  
 44  NSString *const NSPersistentStoreSaveConflictsErrorKey = @"conflictList";
 45  
 46  NSString *const NSInferMappingModelAutomaticallyOption =
 47          @"NSInferMappingModelAutomaticallyOption";
 48  NSString *const NSReadOnlyPersistentStoreOption =
 49          @"NSReadOnlyPersistentStoreOption";
 50  NSString *const NSSQLiteManualVacuumOption = @"NSSQLiteManualVacuumOption";
 51  NSString *const NSStoreModelVersionHashesKey =
 52          @"NSStoreModelVersionHashesKey";
 53  
 54  @implementation NSPersistentStoreCoordinator
 55  
 56  static NSMutableDictionary *_storeTypes = nil;
 57  
 58  + (void) initialize {
 59      if (self == [NSPersistentStoreCoordinator class]) {
 60          _storeTypes = [NSMutableDictionary new];
 61          [_storeTypes setObject: [NSInMemoryPersistentStore class]
 62                          forKey: NSInMemoryStoreType];
 63          [_storeTypes setObject: [NSXMLPersistentStore class]
 64                          forKey: NSXMLStoreType];
 65      }
 66  }
 67  
 68  + (NSDictionary *) registeredStoreTypes {
 69      return _storeTypes;
 70  }
 71  
 72  + (void) registerStoreClass: (Class) storeClass
 73                 forStoreType: (NSString *) storeType
 74  {
 75      [_storeTypes setObject: storeClass forKey: storeType];
 76  }
 77  
 78  - initWithManagedObjectModel: (NSManagedObjectModel *) model {
 79      _lock = [[NSLock alloc] init];
 80      _model = [model retain];
 81      _stores = [[NSMutableArray alloc] init];
 82      return self;
 83  }
 84  
 85  - (void) dealloc {
 86      [_lock release];
 87      [_model release];
 88      [_stores release];
 89      [super dealloc];
 90  }
 91  
 92  - (NSManagedObjectModel *) managedObjectModel {
 93      return _model;
 94  }
 95  
 96  - (NSPersistentStore *) addPersistentStoreWithType: (NSString *) storeType
 97                                       configuration: (NSString *) configuration
 98                                                 URL: (NSURL *) storeURL
 99                                             options: (NSDictionary *) options
100                                               error: (NSError **) error
101  {
102      /* It appears that this method will determine the store type if it is nil */
103      if (storeType == nil) {
104  
105          for (Class class in [_storeTypes allValues]) {
106              NSDictionary *metadata =
107                      [class metadataForPersistentStoreWithURL: storeURL
108                                                         error: nil];
109              if ((storeType = [metadata objectForKey: NSStoreTypeKey]) != nil)
110                  break;
111          }
112      }
113  
114      Class class = [[[self class] registeredStoreTypes] objectForKey: storeType];
115      NSAtomicStore *store = [[[class alloc]
116              initWithPersistentStoreCoordinator: self
117                               configurationName: configuration
118                                             URL: storeURL
119                                         options: options] autorelease];
120  
121      if (![store load: error])
122          return nil;
123  
124      [_stores addObject: store];
125  
126      return store;
127  }
128  
129  - (BOOL) setURL: (NSURL *) url forPersistentStore: (NSPersistentStore *) store {
130      [store setURL: url];
131      return YES;
132  }
133  
134  - (BOOL) removePersistentStore: (NSPersistentStore *) store
135                           error: (NSError **) error
136  {
137      NSArray *remove = [NSArray arrayWithObject: store];
138      NSDictionary *userInfo =
139              [NSDictionary dictionaryWithObject: remove
140                                          forKey: NSRemovedPersistentStoresKey];
141  
142      [store willRemoveFromPersistentStoreCoordinator: self];
143  
144      [[NSNotificationCenter defaultCenter]
145              postNotificationName:
146                      NSPersistentStoreCoordinatorStoresDidChangeNotification
147                            object: self
148                          userInfo: userInfo];
149  
150      [_stores removeObjectIdenticalTo: store];
151  
152      return YES;
153  }
154  
155  - (NSPersistentStore *) migratePersistentStore: (NSPersistentStore *) store
156                                           toURL: (NSURL *) URL
157                                         options: (NSDictionary *) options
158                                        withType: (NSString *) storeType
159                                           error: (NSError **) error
160  {
161      NSUnimplementedMethod();
162      return nil;
163  }
164  
165  - (NSArray *) persistentStores {
166      return _stores;
167  }
168  
169  - (NSPersistentStore *) persistentStoreForURL: (NSURL *) URL {
170      /* This only returns a store if it exists in the coordinator */
171  
172      for (NSPersistentStore *check in _stores) {
173          if ([[check URL] isEqual: URL])
174              return check;
175      }
176  
177      return nil;
178  }
179  
180  - (NSURL *) URLForPersistentStore: (NSPersistentStore *) store {
181      return [store URL];
182  }
183  
184  - (void) lock {
185      [_lock lock];
186  }
187  
188  - (BOOL) tryLock {
189      return [_lock tryLock];
190  }
191  
192  - (void) unlock {
193      [_lock unlock];
194  }
195  
196  - (NSDictionary *) metadataForPersistentStore: (NSPersistentStore *) store {
197      return [store metadata];
198  }
199  
200  - (void) setMetadata: (NSDictionary *) value
201          forPersistentStore: (NSPersistentStore *) store
202  {
203      [store setMetadata: value];
204  }
205  
206  + (BOOL) setMetadata: (NSDictionary *) metadata
207          forPersistentStoreOfType: (NSString *) storeType
208                               URL: (NSURL *) url
209                             error: (NSError **) error
210  {
211      Class check = [[self registeredStoreTypes] objectForKey: storeType];
212  
213      return [check setMetadata: metadata
214              forPersistentStoreWithURL: url
215                                  error: error];
216  }
217  
218  + (NSDictionary *) metadataForPersistentStoreOfType: (NSString *) storeType
219                                                  URL: (NSURL *) url
220                                                error: (NSError **) error
221  {
222      Class check = [[self registeredStoreTypes] objectForKey: storeType];
223  
224      return [check metadataForPersistentStoreWithURL: url error: error];
225  }
226  
227  - (NSPersistentStore *) _persistentStoreWithIdentifier: (NSString *) identifier
228  {
229      for (NSPersistentStore *check in _stores)
230          if ([[check identifier] isEqualToString: identifier])
231              return check;
232  
233      return nil;
234  }
235  
236  - (NSPersistentStore *) _persistentStoreForObjectID:
237          (NSManagedObjectID *) objectID
238  {
239      NSEntityDescription *entity = [objectID entity];
240      NSString *storeIdentifier = [objectID storeIdentifier];
241      NSPersistentStore *check =
242              [self _persistentStoreWithIdentifier: storeIdentifier];
243  
244      if (check != nil)
245          return check;
246  
247      NSManagedObjectModel *model = [self managedObjectModel];
248  
249      if ([_stores count] == 0) {
250          [NSException
251                   raise: NSInvalidArgumentException
252                  format: @"-[%@ %s] no persistent stores", [self class], _cmd];
253          return nil;
254      }
255  
256      for (check in _stores) {
257          NSString *configurationName = [check configurationName];
258  
259          if (configurationName == nil) {
260              NSArray *entities =
261                      [model entitiesForConfiguration: configurationName];
262  
263              if ([entities containsObject: entity])
264                  return check;
265          }
266      }
267  
268      return [_stores objectAtIndex: 0];
269  }
270  
271  - (NSPersistentStore *) _persistentStoreForObject: (NSManagedObject *) object {
272      return [self _persistentStoreForObjectID: [object objectID]];
273  }
274  
275  - (NSManagedObjectID *) managedObjectIDForURIRepresentation: (NSURL *) URL {
276      NSString *scheme = [URL scheme];
277      NSString *host = [URL host];
278      NSString *path = [URL path];
279      NSString *referenceObject = [path lastPathComponent];
280      NSString *entityName =
281              [[path stringByDeletingLastPathComponent] lastPathComponent];
282      NSManagedObjectModel *model = [self managedObjectModel];
283      NSEntityDescription *entity =
284              [[model entitiesByName] objectForKey: entityName];
285  
286      return [(NSAtomicStore *) [self _persistentStoreWithIdentifier: host]
287              objectIDForEntity: entity
288                referenceObject: referenceObject];
289  }
290  
291  @end