~ubuntu-branches/ubuntu/edgy/sope/edgy

« back to all changes in this revision

Viewing changes to sope-gdl1/GDLAccess/EODatabase.m

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Ley
  • Date: 2005-08-19 16:53:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050819165331-hs683wz1osm708pw
Tags: upstream-4.4rc.2
ImportĀ upstreamĀ versionĀ 4.4rc.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   EODatabase.m
 
3
 
 
4
   Copyright (C) 1996 Free Software Foundation, Inc.
 
5
 
 
6
   Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
 
7
   Date: 1996
 
8
 
 
9
   This file is part of the GNUstep Database Library.
 
10
 
 
11
   This library is free software; you can redistribute it and/or
 
12
   modify it under the terms of the GNU Library General Public
 
13
   License as published by the Free Software Foundation; either
 
14
   version 2 of the License, or (at your option) any later version.
 
15
 
 
16
   This library is distributed in the hope that it will be useful,
 
17
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
19
   Library General Public License for more details.
 
20
 
 
21
   You should have received a copy of the GNU Library General Public
 
22
   License along with this library; see the file COPYING.LIB.
 
23
   If not, write to the Free Software Foundation,
 
24
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
25
*/
 
26
 
 
27
#import "common.h"
 
28
#import "EODatabase.h"
 
29
#import "EOAdaptor.h"
 
30
#import "EOModel.h"
 
31
#import "EOEntity.h"
 
32
#import "EOGenericRecord.h"
 
33
#import "EODatabaseContext.h"
 
34
#import "EOObjectUniquer.h"
 
35
#import "EODatabaseFault.h"
 
36
 
 
37
NSTimeInterval NSDistantPastTimeInterval = 0.0;
 
38
 
 
39
@implementation EODatabase
 
40
 
 
41
// Database Global Methods
 
42
 
 
43
static NSMutableArray  *databaseInstances = nil;
 
44
static NSRecursiveLock *lock              = nil;
 
45
 
 
46
+ (void)initialize {
 
47
  static BOOL isInitialized = NO;
 
48
  // THREAD
 
49
  if (!isInitialized) {
 
50
    isInitialized = YES;
 
51
    databaseInstances = [[NSMutableArray alloc] init];
 
52
    lock              = [[NSRecursiveLock alloc] init];
 
53
  }
 
54
}
 
55
 
 
56
static inline void _addDatabaseInstance(EODatabase *_db) {
 
57
  [lock lock];
 
58
  [databaseInstances addObject:[NSValue valueWithNonretainedObject:_db]];
 
59
  [lock unlock];
 
60
}
 
61
static inline void _removeDatabaseInstance(EODatabase *_db) {
 
62
  [lock lock];
 
63
  {
 
64
    int i;
 
65
    
 
66
    for (i = [databaseInstances count] - 1; i >= 0; i--) {
 
67
      EODatabase *db;
 
68
 
 
69
      db = [[databaseInstances objectAtIndex:i] nonretainedObjectValue];
 
70
      if (db == _db) {
 
71
        [databaseInstances removeObjectAtIndex:i];
 
72
        break;
 
73
      }
 
74
    }
 
75
  }
 
76
  [lock unlock];
 
77
}
 
78
 
 
79
/*
 
80
 * Initializing new instances
 
81
 */
 
82
 
 
83
- (id)initWithAdaptor:(EOAdaptor *)_adaptor {
 
84
  if (_adaptor == nil) {
 
85
    AUTORELEASE(self);
 
86
    return nil;
 
87
  }
 
88
    
 
89
  self->adaptor           = RETAIN(_adaptor);
 
90
  self->objectsDictionary = [[EOObjectUniquer allocWithZone:[self zone]] init];
 
91
  self->contexts          = [[NSMutableArray  allocWithZone:[self zone]] init];
 
92
    
 
93
  self->flags.isUniquingObjects  = YES;
 
94
  self->flags.isKeepingSnapshots = YES;
 
95
  self->flags.isLoggingWarnings  = YES;
 
96
 
 
97
  _addDatabaseInstance(self);
 
98
    
 
99
  return self;
 
100
}
 
101
 
 
102
- (id)initWithModel:(EOModel *)_model {
 
103
  return [self initWithAdaptor:[EOAdaptor adaptorWithModel:_model]];
 
104
}
 
105
- (id)init {
 
106
  return [self initWithAdaptor:nil];
 
107
}
 
108
 
 
109
- (void)dealloc {
 
110
  _removeDatabaseInstance(self);
 
111
  
 
112
  RELEASE(self->adaptor);
 
113
  RELEASE(self->objectsDictionary);
 
114
  RELEASE(self->contexts);
 
115
  [super dealloc];
 
116
}
 
117
 
 
118
// accessors
 
119
 
 
120
- (EOAdaptor *)adaptor {
 
121
  return self->adaptor;
 
122
}
 
123
 
 
124
- (EOObjectUniquer *)objectUniquer {
 
125
  return self->objectsDictionary;
 
126
}
 
127
 
 
128
// Checking connection status
 
129
 
 
130
- (BOOL)hasOpenChannels {
 
131
  int i;
 
132
    
 
133
  for (i = ([self->contexts count] - 1); i >= 0; i--) {
 
134
    if ([[[self->contexts objectAtIndex:i] nonretainedObjectValue]
 
135
                          hasOpenChannels])
 
136
      return YES;
 
137
  }
 
138
  return NO;
 
139
}
 
140
 
 
141
/*
 
142
 * Getting the database contexts
 
143
 */
 
144
 
 
145
- (id)createContext {
 
146
  return AUTORELEASE([[EODatabaseContext alloc] initWithDatabase:self]);
 
147
}
 
148
 
 
149
- (NSArray *)contexts {
 
150
  NSMutableArray *array = nil;
 
151
  int i, n;
 
152
 
 
153
  n = [self->contexts count];
 
154
  array = [[NSMutableArray alloc] initWithCapacity:n];
 
155
    
 
156
  for (i = 0; i < n; i++) {
 
157
    EODatabaseContext *ctx;
 
158
 
 
159
    ctx = [[self->contexts objectAtIndex:i] nonretainedObjectValue];
 
160
    [array addObject:ctx];
 
161
  }
 
162
  return AUTORELEASE(array);
 
163
}
 
164
 
 
165
- (void)contextDidInit:(id)_context {
 
166
  [self->contexts addObject:[NSValue valueWithNonretainedObject:_context]];
 
167
}
 
168
 
 
169
- (void)contextWillDealloc:(id)aContext {
 
170
  int i;
 
171
    
 
172
  for (i = [self->contexts count]-1; i >= 0; i--) {
 
173
    if ([[self->contexts objectAtIndex:i] nonretainedObjectValue] == aContext) {
 
174
      [self->contexts removeObjectAtIndex:i];
 
175
      break;
 
176
    }
 
177
  }
 
178
}
 
179
 
 
180
/*
 
181
 * Uniquing/snapshotting
 
182
 */
 
183
 
 
184
- (void)setUniquesObjects:(BOOL)yn {
 
185
  if ([self hasOpenChannels]) {
 
186
    [NSException raise:NSInvalidArgumentException
 
187
                 format:
 
188
              @"EODatabase:%x: All channels must be closed when changing "
 
189
              @"uniquing mode in the EODatabase, "
 
190
              @"in [EODatabase setUniquesObjects:]",
 
191
                 self];
 
192
  }
 
193
 
 
194
  if ((!yn) && (self->flags.isUniquingObjects))
 
195
    [self->objectsDictionary forgetAllObjects];
 
196
  self->flags.isUniquingObjects = yn;
 
197
}
 
198
- (BOOL)uniquesObjects {
 
199
  return self->flags.isUniquingObjects;
 
200
}
 
201
 
 
202
- (void)setKeepsSnapshots:(BOOL)yn {
 
203
  if ([self hasOpenChannels]) {
 
204
    [NSException raise:NSInvalidArgumentException
 
205
                 format:
 
206
              @"EODatabase:%x: All channels must be closed when changing "
 
207
              @"snapshoting mode in the EODatabase, "
 
208
              @"in [EODatabase setKeepsSnapshots:]",
 
209
                 self];
 
210
  }
 
211
 
 
212
  if ((yn == NO) && self->flags.isKeepingSnapshots)
 
213
    [self->objectsDictionary forgetAllSnapshots];
 
214
  
 
215
  self->flags.isKeepingSnapshots = yn;
 
216
}
 
217
- (BOOL)keepsSnapshots {
 
218
  return self->flags.isKeepingSnapshots;
 
219
}
 
220
 
 
221
// ******************** Handle Objects ********************
 
222
 
 
223
- (void)forgetAllObjects {
 
224
  [self->objectsDictionary forgetAllObjects];
 
225
}
 
226
 
 
227
+ (void)forgetObject:(id)_object {
 
228
  [EOObjectUniquer forgetObject:_object];
 
229
 
 
230
  [lock lock];
 
231
  {
 
232
    int i;
 
233
    
 
234
    for (i = [databaseInstances count] - 1; i >= 0; i--) {
 
235
      EODatabase *db;
 
236
 
 
237
      db = [[databaseInstances objectAtIndex:i] nonretainedObjectValue];
 
238
      [db forgetObject:_object];
 
239
    }
 
240
  }
 
241
  [lock unlock];
 
242
}
 
243
 
 
244
- (void)forgetObject:(id)_object {
 
245
  /*
 
246
    NSLog(@"DB[0x%08X]: forget object 0x%08X<%s> entity=%@",
 
247
        self, _object, class_get_class_name(*(Class *)_object),
 
248
        [[_object entity] name]);
 
249
  */
 
250
  [self->objectsDictionary forgetObject:_object];
 
251
}
 
252
 
 
253
- (void)forgetAllSnapshots {
 
254
  [self->objectsDictionary forgetAllSnapshots];
 
255
}
 
256
 
 
257
- (id)objectForPrimaryKey:(NSDictionary *)_key entity:(EOEntity *)_entity {
 
258
  if (self->flags.isUniquingObjects && (_key != nil) && (_entity != nil)) {
 
259
    _key = [_entity primaryKeyForRow:_key];
 
260
    if (_key == nil)
 
261
      return nil;
 
262
    else {
 
263
      id object = [self->objectsDictionary objectForPrimaryKey:_key entity:_entity];
 
264
      
 
265
#if 0
 
266
      if (object) {
 
267
        if (![object isKindOfClass:[EOGenericRecord class]])
 
268
          NSLog(@"object 0x%08X pkey=%@ entity=%@", object, _key, _entity);
 
269
      }
 
270
#endif
 
271
      return object;
 
272
    }
 
273
  }
 
274
  return nil;
 
275
}
 
276
 
 
277
- (NSDictionary *)snapshotForObject:_object {
 
278
  EOUniquerRecord* rec = [self->objectsDictionary recordForObject:_object];
 
279
    
 
280
  return rec ? rec->snapshot : nil;
 
281
}
 
282
 
 
283
- (NSDictionary *)primaryKeyForObject:(id)_object {
 
284
  EOUniquerRecord* rec = [self->objectsDictionary recordForObject:_object];
 
285
    
 
286
  return rec ? rec->pkey : nil;
 
287
}
 
288
 
 
289
- (void)primaryKey:(NSDictionary**)_key
 
290
  andSnapshot:(NSDictionary**)_snapshot
 
291
  forObject:(id)_object {
 
292
 
 
293
  EOUniquerRecord *rec = [self->objectsDictionary recordForObject:_object];
 
294
    
 
295
  if (rec) {
 
296
    if (_key)      *_key      = rec->pkey;
 
297
    if (_snapshot) *_snapshot = rec->snapshot;
 
298
  }
 
299
  else {
 
300
    if (_key)      *_key      = nil;
 
301
    if (_snapshot) *_snapshot = nil;
 
302
  }
 
303
}
 
304
 
 
305
- (void)recordObject:(id)_object
 
306
  primaryKey:(NSDictionary *)_key
 
307
  snapshot:(NSDictionary *)_snapshot {
 
308
 
 
309
  EOEntity *entity;
 
310
 
 
311
  entity = [_object respondsToSelector:@selector(entity)]
 
312
    ? [_object entity]
 
313
    : [[self->adaptor model] entityForObject:_object];
 
314
    
 
315
  [self recordObject:_object
 
316
        primaryKey:_key
 
317
        entity:entity
 
318
        snapshot:_snapshot];
 
319
}
 
320
 
 
321
- (void)recordObject:(id)_object
 
322
  primaryKey:(NSDictionary *)_key
 
323
  entity:(EOEntity *)_entity
 
324
  snapshot:(NSDictionary *)_snapshot {
 
325
 
 
326
  if (_object == nil) {
 
327
    [NSException raise:NSInvalidArgumentException
 
328
                 format:
 
329
                   @"EODatabase:%x: Cannot record null object, "
 
330
                   @"in [EODatabase recordObject:primaryKey:entity:snapshot:]",
 
331
                   self];
 
332
  }
 
333
  if ((_entity == nil) && self->flags.isUniquingObjects) {
 
334
    [NSException raise:NSInvalidArgumentException
 
335
                 format:
 
336
              @"EODatabase:%x: Cannot record object with null entity "
 
337
              @"when the database is uniquing objects, "
 
338
              @"in [EODatabase recordObject:primaryKey:entity:snapshot:]",
 
339
                 self];
 
340
  }
 
341
  _key = [_entity primaryKeyForRow:_key];
 
342
  if ((_key == nil) && self->flags.isUniquingObjects) {
 
343
    [NSException raise:NSInvalidArgumentException
 
344
                 format:
 
345
              @"EODatabase:%x: Cannot record object with null key "
 
346
              @"when the database is uniquing objects, "
 
347
              @"in [EODatabase recordObject:primaryKey:entity:snapshot:]",
 
348
                 self];
 
349
  }
 
350
  if ((_snapshot == nil) && self->flags.isKeepingSnapshots) {
 
351
    [NSException raise:NSInvalidArgumentException
 
352
                 format:
 
353
              @"EODatabase:%x: Cannot record object with null snapshot "
 
354
              @"when the database is keeping snapshots, "
 
355
              @"in [EODatabase recordObject:primaryKey:entity:snapshot:]",
 
356
                 self];
 
357
  }
 
358
 
 
359
  [objectsDictionary recordObject:_object 
 
360
                     primaryKey:self->flags.isUniquingObjects?_key:nil
 
361
                     entity:self->flags.isUniquingObjects ?_entity:nil
 
362
                     snapshot:self->flags.isKeepingSnapshots?_snapshot:nil];
 
363
}
 
364
 
 
365
- (BOOL)isObject:(id)_object 
 
366
  updatedOutsideContext:(EODatabaseContext *)_context 
 
367
{
 
368
  int i;
 
369
    
 
370
  for (i = [contexts count] - 1; i >= 0; i--) {
 
371
    EODatabaseContext *ctx;
 
372
 
 
373
    ctx = [[self->contexts objectAtIndex:i] nonretainedObjectValue];
 
374
        
 
375
    if ((ctx != _context) && [ctx isObjectUpdated:_object])
 
376
      return YES;
 
377
  }
 
378
  return NO;
 
379
}
 
380
 
 
381
// ******************** Error messages ********************
 
382
 
 
383
- (void)setLogsErrorMessages:(BOOL)yn {
 
384
  self->flags.isLoggingWarnings = yn;
 
385
}
 
386
- (BOOL)logsErrorMessages {
 
387
  return self->flags.isLoggingWarnings;
 
388
}
 
389
 
 
390
- (void)reportErrorFormat:(NSString*)format, ... {
 
391
  va_list va;
 
392
    
 
393
  va_start(va, format);
 
394
  [self reportErrorFormat:format arguments:va];
 
395
  va_end(va);
 
396
}
 
397
 
 
398
- (void)reportErrorFormat:(NSString*)format arguments:(va_list)arguments {
 
399
  [self reportError:AUTORELEASE([[NSString alloc] initWithFormat:format 
 
400
                                                  arguments:arguments])];
 
401
}
 
402
 
 
403
- (void)reportError:(NSString*)error {
 
404
  if (self->flags.isLoggingWarnings)
 
405
    NSLog(@"EODatabase:%x:%@", self, error);
 
406
}
 
407
 
 
408
@end /* EODatabase */
 
409
 
 
410
@implementation EODatabase(EOF2Additions)
 
411
 
 
412
- (NSArray *)models {
 
413
  EOModel *model;
 
414
 
 
415
  model = [[self adaptor] model];
 
416
  return model ? [NSArray arrayWithObject:model] : nil;
 
417
}
 
418
 
 
419
- (void)addModel:(EOModel *)_model {
 
420
  EOModel *model;
 
421
 
 
422
  model = [[self adaptor] model];
 
423
 
 
424
  if (model == nil)
 
425
    [[self adaptor] setModel:_model];
 
426
  else
 
427
    [self notImplemented:_cmd];
 
428
}
 
429
 
 
430
- (BOOL)addModelIfCompatible:(EOModel *)_model {
 
431
  NSEnumerator *e;
 
432
  EOModel *m;
 
433
 
 
434
  if (![[self adaptor] canServiceModel:_model])
 
435
    return NO;
 
436
 
 
437
  e = [[self models] objectEnumerator];
 
438
  while ((m = [e nextObject])) {
 
439
    if (m == _model)
 
440
      return YES;
 
441
 
 
442
    if (![[m adaptorName] isEqualToString:[_model adaptorName]])
 
443
      return NO;
 
444
  }
 
445
  
 
446
  [self addModel:_model];
 
447
  return YES;
 
448
}
 
449
 
 
450
- (EOEntity *)entityForObject:(id)_object {
 
451
  return [[[self adaptor] model] entityForObject:_object];
 
452
}
 
453
- (EOEntity *)entityNamed:(NSString *)_name {
 
454
  return [[[self adaptor] model] entityNamed:_name];
 
455
}
 
456
 
 
457
/* snapshots */
 
458
 
 
459
- (void)forgetSnapshotsForGlobalIDs:(NSArray *)_gids {
 
460
  NSEnumerator *e;
 
461
  EOGlobalID   *gid;
 
462
 
 
463
  e = [_gids objectEnumerator];
 
464
  while ((gid = [e nextObject]))
 
465
    [self forgetSnapshotsForGlobalID:gid];
 
466
}
 
467
- (void)forgetSnapshotsForGlobalID:(EOGlobalID *)_gid {
 
468
  [self notImplemented:_cmd];
 
469
}
 
470
 
 
471
- (void)recordSnapshot:(NSDictionary *)_snapshot forGlobalID:(EOGlobalID *)_gid {
 
472
  [self notImplemented:_cmd];
 
473
}
 
474
- (void)recordSnapshots:(NSDictionary *)_snapshots {
 
475
  NSEnumerator *gids;
 
476
  EOGlobalID   *gid;
 
477
 
 
478
  gids = [_snapshots keyEnumerator];
 
479
  while ((gid = [gids nextObject]))
 
480
    [self recordSnapshot:[_snapshots objectForKey:gid] forGlobalID:gid];
 
481
}
 
482
 
 
483
- (void)recordSnapshot:(NSArray *)_gids
 
484
  forSourceGlobalID:(EOGlobalID *)_gid
 
485
  relationshipName:(NSString *)_name
 
486
{
 
487
  /* to-many snapshot */
 
488
  [self notImplemented:_cmd];
 
489
}
 
490
- (void)recordToManySnapshots:(NSDictionary *)_snapshots {
 
491
  NSEnumerator *gids;
 
492
  EOGlobalID   *gid;
 
493
 
 
494
  gids = [_snapshots keyEnumerator];
 
495
  while ((gid = [gids nextObject])) {
 
496
    NSDictionary *d;
 
497
    NSEnumerator *relNames;
 
498
    NSString     *relName;
 
499
    
 
500
    d = [_snapshots objectForKey:gid];
 
501
    relNames = [d keyEnumerator];
 
502
 
 
503
    while ((relName = [relNames nextObject])) {
 
504
      [self recordSnapshot:[d objectForKey:relName]
 
505
            forSourceGlobalID:gid
 
506
            relationshipName:relName];
 
507
    }
 
508
  }
 
509
}
 
510
 
 
511
- (NSDictionary *)snapshotForGlobalID:(EOGlobalID *)_gid
 
512
  after:(NSTimeInterval)_duration
 
513
{
 
514
  NSLog(@"ERROR(%s): subclasses must override this method!",
 
515
        __PRETTY_FUNCTION__);
 
516
  return nil;
 
517
}
 
518
 
 
519
- (NSDictionary *)snapshotForGlobalID:(EOGlobalID *)_gid {
 
520
  return [self snapshotForGlobalID:_gid after:NSDistantPastTimeInterval];
 
521
}
 
522
 
 
523
@end /* EODatabase(EOF2Additions) */