mirror of
https://github.com/gnustep/libs-gdl2.git
synced 2025-04-22 12:55:44 +00:00
* EOControl/EOSharedEditingContext.[hm]: New files.
* EOControl/EOEditingContext.[hm]: Use EOSharedEditingContext. (sharedEditingContext, setSharedEditingContext:): New methods. (-initWithParentObjectStore:): Handle EOSharedEditingContext. (-dealloc, -faultForGlobalID:editingContext:): Ditto. (-objectForGlobalID:, -globalIDForObject:): Ditto. (-initializeObject:withGlobalID:editingContext:): Ditto. (-refaultObject:withGlobalID:editingContext:): Ditto. (-_processInitializedObjectsInSharedContext:): New method. (-_defaultEditingContextNowInitialized:): Ditto. (-_objectsInitializedInSharedContext:) Ditto. (-_defaultSharedEditingContextWasInitialized:) Ditto. * EOControl/EOControl.h: Added EOSharedEditingContext.h. * EOControl/GNUmakefile: Added EOSharedEditingContext.[hm]. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@22117 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
2bdd595b3c
commit
1e70ef602c
8 changed files with 1053 additions and 64 deletions
17
ChangeLog
17
ChangeLog
|
@ -1,3 +1,20 @@
|
|||
2005-11-28 David Ayers <d.ayers@inode.at>
|
||||
|
||||
* EOControl/EOSharedEditingContext.[hm]: New files.
|
||||
* EOControl/EOEditingContext.[hm]: Use EOSharedEditingContext.
|
||||
(sharedEditingContext, setSharedEditingContext:): New methods.
|
||||
(-initWithParentObjectStore:): Handle EOSharedEditingContext.
|
||||
(-dealloc, -faultForGlobalID:editingContext:): Ditto.
|
||||
(-objectForGlobalID:, -globalIDForObject:): Ditto.
|
||||
(-initializeObject:withGlobalID:editingContext:): Ditto.
|
||||
(-refaultObject:withGlobalID:editingContext:): Ditto.
|
||||
(-_processInitializedObjectsInSharedContext:): New method.
|
||||
(-_defaultEditingContextNowInitialized:): Ditto.
|
||||
(-_objectsInitializedInSharedContext:) Ditto.
|
||||
(-_defaultSharedEditingContextWasInitialized:) Ditto.
|
||||
* EOControl/EOControl.h: Added EOSharedEditingContext.h.
|
||||
* EOControl/GNUmakefile: Added EOSharedEditingContext.[hm].
|
||||
|
||||
2005-11-02 David Ayers <d.ayers@inode.at>
|
||||
|
||||
* EOAdaptors/Postgres95/Postgres95Adaptor.m (typeNames): Add
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include <EOControl/EOObjectStoreCoordinator.h>
|
||||
#include <EOControl/EOFault.h>
|
||||
#include <EOControl/EOEditingContext.h>
|
||||
#include <EOControl/EOSharedEditingContext.h>
|
||||
#include <EOControl/EODataSource.h>
|
||||
#include <EOControl/EOArrayDataSource.h>
|
||||
#include <EOControl/EODetailDataSource.h>
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
@class NSAutoreleasePool;
|
||||
@class NSUndoManager;
|
||||
|
||||
@class EOSharedEditingContext;
|
||||
|
||||
@interface EOEditingContext : EOObjectStore <EOObserving>
|
||||
{
|
||||
|
@ -98,8 +99,8 @@
|
|||
unsigned willSaveChanges:1;
|
||||
} _delegateRespondsTo;
|
||||
|
||||
NSRecursiveLock*_lock;
|
||||
id _sharedContext;
|
||||
NSRecursiveLock *_lock;
|
||||
EOSharedEditingContext *_sharedContext;
|
||||
int _lockCount;
|
||||
id _notificationQueue;
|
||||
NSAutoreleasePool * _lockPool;
|
||||
|
@ -177,6 +178,9 @@
|
|||
- (BOOL)locksObjectsBeforeFirstModification;
|
||||
- (void)setLocksObjectsBeforeFirstModification: (BOOL)yn;
|
||||
|
||||
- (EOSharedEditingContext *)sharedEditingContext;
|
||||
- (void)setSharedEditingContext:(EOSharedEditingContext *)sharedEditingContext;
|
||||
|
||||
/** Returns a dictionary containing a snapshot of object
|
||||
that reflects its committed values (last values putted in
|
||||
the database; i.e. values before changes were made on the
|
||||
|
|
|
@ -44,16 +44,17 @@ RCS_ID("$Id$")
|
|||
|
||||
#include <GNUstepBase/GSLock.h>
|
||||
|
||||
#include <EOControl/EOEditingContext.h>
|
||||
#include <EOControl/EOObjectStoreCoordinator.h>
|
||||
#include <EOControl/EOGlobalID.h>
|
||||
#include <EOControl/EOClassDescription.h>
|
||||
#include <EOControl/EOKeyValueCoding.h>
|
||||
#include <EOControl/EOFault.h>
|
||||
#include <EOControl/EONull.h>
|
||||
#include <EOControl/EONSAddOns.h>
|
||||
#include <EOControl/EODeprecated.h>
|
||||
#include <EOControl/EODebug.h>
|
||||
#include "EOEditingContext.h"
|
||||
#include "EOSharedEditingContext.h"
|
||||
#include "EOObjectStoreCoordinator.h"
|
||||
#include "EOGlobalID.h"
|
||||
#include "EOClassDescription.h"
|
||||
#include "EOKeyValueCoding.h"
|
||||
#include "EOFault.h"
|
||||
#include "EONull.h"
|
||||
#include "EONSAddOns.h"
|
||||
#include "EODeprecated.h"
|
||||
#include "EODebug.h"
|
||||
|
||||
#include "EOPrivate.h"
|
||||
|
||||
|
@ -71,42 +72,48 @@ RCS_ID("$Id$")
|
|||
@interface EOEntityClassDescription : EOClassDescription
|
||||
- (NSObject *) entity;
|
||||
@end
|
||||
@interface EOSharedEditingContext (Privat)
|
||||
+ (EOSharedEditingContext *)_defaultSharedEditingContext;
|
||||
@end
|
||||
|
||||
@interface EOEditingContext(EOEditingContextPrivate)
|
||||
- (void) incrementUndoTransactionID;
|
||||
- (BOOL) handleError: (NSException *)exception;
|
||||
- (BOOL) handleErrors: (NSArray *)exceptions;
|
||||
- (void)incrementUndoTransactionID;
|
||||
- (BOOL)handleError: (NSException *)exception;
|
||||
- (BOOL)handleErrors: (NSArray *)exceptions;
|
||||
|
||||
- (void) _enqueueEndOfEventNotification;
|
||||
- (void) _sendOrEnqueueNotification: (NSNotification *)notification
|
||||
selector: (SEL)selector;
|
||||
- (void)_enqueueEndOfEventNotification;
|
||||
- (void)_sendOrEnqueueNotification: (NSNotification *)notification
|
||||
selector: (SEL)selector;
|
||||
|
||||
- (void) _insertObject: (id)object
|
||||
withGlobalID: (EOGlobalID *)gid;
|
||||
- (void)_insertObject: (id)object
|
||||
withGlobalID: (EOGlobalID *)gid;
|
||||
|
||||
- (void) _processObjectStoreChanges: (NSDictionary *)changes;
|
||||
- (void) _processDeletedObjects;
|
||||
- (void) _processOwnedObjectsUsingChangeTable: (NSHashTable*)changeTable
|
||||
deleteTable: (NSHashTable*)deleteTable;
|
||||
- (void)_processObjectStoreChanges: (NSDictionary *)changes;
|
||||
- (void)_processDeletedObjects;
|
||||
- (void)_processOwnedObjectsUsingChangeTable: (NSHashTable*)changeTable
|
||||
deleteTable: (NSHashTable*)deleteTable;
|
||||
- (void)_processNotificationQueue;
|
||||
|
||||
- (void) _observeUndoManagerNotifications;
|
||||
- (void)_observeUndoManagerNotifications;
|
||||
|
||||
- (void) _registerClearStateWithUndoManager;
|
||||
- (void)_registerClearStateWithUndoManager;
|
||||
|
||||
- (void) _forgetObjectWithGlobalID:(EOGlobalID *)gid;
|
||||
- (void)_forgetObjectWithGlobalID:(EOGlobalID *)gid;
|
||||
|
||||
- (void) _invalidateObject:(id)obj withGlobalID: (EOGlobalID *)gid;
|
||||
- (void) _invalidateObjectsWithGlobalIDs: (NSArray*)gids;
|
||||
- (NSDictionary *) _objectBasedChangeInfoForGIDInfo: (NSDictionary *)changes;
|
||||
- (void)_invalidateObject:(id)obj withGlobalID: (EOGlobalID *)gid;
|
||||
- (void)_invalidateObjectsWithGlobalIDs: (NSArray*)gids;
|
||||
- (NSDictionary *)_objectBasedChangeInfoForGIDInfo: (NSDictionary *)changes;
|
||||
|
||||
- (NSMutableSet *)_mutableSetFromToManyArray: (NSArray *)array;
|
||||
- (NSArray *)_uncommittedChangesForObject: (id)obj
|
||||
fromSnapshot: (NSDictionary *)snapshot;
|
||||
- (NSArray *)_changesFromInvalidatingObjectsWithGlobalIDs: (NSArray *)globalIDs;
|
||||
|
||||
- (void) _resetAllChanges;
|
||||
|
||||
- (void)_resetAllChanges;
|
||||
- (void)_defaultSharedEditingContextWasInitialized:(NSNotification *)notification;
|
||||
- (void)_defaultEditingContextNowInitialized:(NSDictionary *)userInfo;
|
||||
- (void)_objectsInitializedInSharedContext:(NSNotification *)notification;
|
||||
- (void)_processInitializedObjectsInSharedContext:(NSDictionary *)userInfo;
|
||||
@end
|
||||
|
||||
@interface EOThreadSafeQueue : NSObject
|
||||
|
@ -172,6 +179,8 @@ NSString *EOObjectsChangedInEditingContextNotification
|
|||
= @"EOObjectsChangedInEditingContextNotification";
|
||||
NSString *EOEditingContextDidSaveChangesNotification
|
||||
= @"EOEditingContextDidSaveChangesNotification";
|
||||
NSString *EOEditingContextDidChangeSharedEditingContextNotification
|
||||
= @"EOEditingContextDidChangeSharedEditingContextNotification";
|
||||
|
||||
/* Local constants */
|
||||
NSString *EOConstObject = @"EOConstObject";
|
||||
|
@ -292,6 +301,7 @@ _mergeValueForKey(id obj, id value,
|
|||
//OK
|
||||
if ((self = [super init]))
|
||||
{
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
_flags.propagatesDeletesAtEndOfEvent = YES; //Default behavior
|
||||
ASSIGN(_objectStore, [EOEditingContext defaultParentObjectStore]); //parentObjectStore instead of defaultParentObjectStore ?
|
||||
|
||||
|
@ -317,46 +327,56 @@ _mergeValueForKey(id obj, id value,
|
|||
_lock = [NSRecursiveLock new];
|
||||
|
||||
_undoManager = [EOUndoManager new];
|
||||
|
||||
[self _observeUndoManagerNotifications];
|
||||
|
||||
_sharedContext = [EOSharedEditingContext _defaultSharedEditingContext];
|
||||
if (_sharedContext)
|
||||
{
|
||||
[nc addObserver: self
|
||||
selector: @selector(_objectsInitializedInSharedContext:)
|
||||
name: EOSharedEditingContextInitializedObjectsNotification
|
||||
object: _sharedContext];
|
||||
}
|
||||
else
|
||||
{
|
||||
[nc addObserver: self
|
||||
selector: @selector(_defaultSharedEditingContextWasInitialized:)
|
||||
name: EODefaultSharedEditingContextWasInitializedNotification
|
||||
object: nil];
|
||||
}
|
||||
|
||||
/*
|
||||
[self setStopsValidationAfterFirstError:YES];
|
||||
[self setPropagatesDeletesAtEndOfEvent:YES];
|
||||
*/
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_objectsChangedInStore:)
|
||||
name: EOObjectsChangedInStoreNotification
|
||||
object: _objectStore];
|
||||
[nc addObserver: self
|
||||
selector: @selector(_objectsChangedInStore:)
|
||||
name: EOObjectsChangedInStoreNotification
|
||||
object: _objectStore];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_invalidatedAllObjectsInStore:)
|
||||
name: EOInvalidatedAllObjectsInStoreNotification
|
||||
object: _objectStore];
|
||||
[nc addObserver: self
|
||||
selector: @selector(_invalidatedAllObjectsInStore:)
|
||||
name: EOInvalidatedAllObjectsInStoreNotification
|
||||
object: _objectStore];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_globalIDChanged:)
|
||||
name: EOGlobalIDChangedNotification
|
||||
object: nil];
|
||||
[nc addObserver: self
|
||||
selector: @selector(_globalIDChanged:)
|
||||
name: EOGlobalIDChangedNotification
|
||||
object: nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_eoNowMultiThreaded:)
|
||||
name: NSWillBecomeMultiThreadedNotification
|
||||
object: nil];
|
||||
/*
|
||||
[nc addObserver: self
|
||||
selector: @selector(_eoNowMultiThreaded:)
|
||||
name: NSWillBecomeMultiThreadedNotification
|
||||
object: nil];
|
||||
/*
|
||||
[self setStopsValidationAfterFirstError:NO];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(_objectsChangedInSubStore:)
|
||||
name:EOObjectsChangedInStoreNotification
|
||||
object:nil];
|
||||
*/
|
||||
[nc addObserver:self
|
||||
selector:@selector(_objectsChangedInSubStore:)
|
||||
name:EOObjectsChangedInStoreNotification
|
||||
object:nil];
|
||||
*/
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -372,7 +392,8 @@ _mergeValueForKey(id obj, id value,
|
|||
{
|
||||
int i,c;
|
||||
NSArray *registeredObjects = [self registeredObjects];
|
||||
|
||||
|
||||
if (_sharedContext) [self setSharedEditingContext: nil];
|
||||
for (i = 0, c = [registeredObjects count]; i < c; i++)
|
||||
{
|
||||
[EOObserverCenter removeObserver:self
|
||||
|
@ -2743,6 +2764,10 @@ _mergeValueForKey(id obj, id value,
|
|||
self, globalID);
|
||||
|
||||
object = NSMapGet(_objectsByGID, globalID);
|
||||
if (object == nil && _sharedContext)
|
||||
{
|
||||
object = [_sharedContext objectForGlobalID: globalID];
|
||||
}
|
||||
|
||||
EOFLOGObjectLevelArgs(@"EOEditingContext",
|
||||
@"EditingContext: %p gid=%@ object=%p",
|
||||
|
@ -2765,6 +2790,10 @@ _mergeValueForKey(id obj, id value,
|
|||
self, _globalIDsByObject, object);
|
||||
|
||||
gid = NSMapGet(_globalIDsByObject, object);
|
||||
if (gid == nil && _sharedContext)
|
||||
{
|
||||
gid = [_sharedContext globalIDForObject: object];
|
||||
}
|
||||
|
||||
EOFLOGObjectLevelArgs(@"EOEditingContext", @"gid=%@", gid);
|
||||
|
||||
|
@ -3149,6 +3178,66 @@ _mergeValueForKey(id obj, id value,
|
|||
_flags.autoLocking = flag;
|
||||
}
|
||||
|
||||
- (EOSharedEditingContext *)sharedEditingContext
|
||||
{
|
||||
return _sharedContext;
|
||||
}
|
||||
- (void)setSharedEditingContext:(EOEditingContext *)sharedEditingContext
|
||||
{
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
NSArray *sharedGIDs;
|
||||
NSArray *localGIDs;
|
||||
_flags.ignoreSharedContextNotifications = YES;
|
||||
if (sharedEditingContext == nil)
|
||||
{
|
||||
[nc removeObserver: self
|
||||
name: EODefaultSharedEditingContextWasInitializedNotification
|
||||
object: nil];
|
||||
}
|
||||
if (_sharedContext == sharedEditingContext) return;
|
||||
if (sharedEditingContext == nil)
|
||||
{
|
||||
[nc removeObserver: self
|
||||
name: EOSharedEditingContextInitializedObjectsNotification
|
||||
object: _sharedContext];
|
||||
/* FIXME: Find out with which configuration this notification is
|
||||
actually processed. */
|
||||
[nc postNotificationName: EOEditingContextDidChangeSharedEditingContextNotification
|
||||
object: self];
|
||||
return;
|
||||
}
|
||||
if (![sharedEditingContext isKindOfClass: [EOSharedEditingContext class]])
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to set illegal object as EOSharedEditingContext"];
|
||||
}
|
||||
sharedGIDs = NSAllMapTableKeys(sharedEditingContext->_globalIDsByObject);
|
||||
localGIDs = NSAllMapTableKeys(_globalIDsByObject);
|
||||
if ([sharedGIDs count] && [localGIDs count])
|
||||
{
|
||||
NSDictionary *userInfo = [NSDictionary dictionaryWithObject: sharedGIDs
|
||||
forKey: @"initialized"];
|
||||
[self _processInitializedObjectsInSharedContext: userInfo];
|
||||
}
|
||||
if (_sharedContext != nil)
|
||||
{
|
||||
[nc removeObserver: self
|
||||
name: EOSharedEditingContextInitializedObjectsNotification
|
||||
object: _sharedContext];
|
||||
}
|
||||
ASSIGN(_sharedContext,sharedEditingContext);
|
||||
[nc addObserver: self
|
||||
selector: @selector(_objectsInitializedInSharedContext:)
|
||||
name: EOSharedEditingContextInitializedObjectsNotification
|
||||
object: _sharedContext];
|
||||
[nc removeObserver: self
|
||||
name: EODefaultSharedEditingContextWasInitializedNotification
|
||||
object: nil];
|
||||
/* FIXME: Find out with which configuration this notification is
|
||||
actually processed. */
|
||||
[nc postNotificationName: EOEditingContextDidChangeSharedEditingContextNotification
|
||||
object: self];
|
||||
}
|
||||
|
||||
// Snapshotting
|
||||
|
||||
|
@ -3264,6 +3353,11 @@ modified state of the object.**/
|
|||
{
|
||||
//OK
|
||||
id object = EOEditingContext_objectForGlobalIDWithImpPtr(self,NULL,globalID);
|
||||
if (!object && _sharedContext)
|
||||
{
|
||||
object = [_sharedContext faultForGlobalID: globalID
|
||||
editingContext: context];
|
||||
}
|
||||
|
||||
if (!object)
|
||||
{
|
||||
|
@ -3390,6 +3484,13 @@ modified state of the object.**/
|
|||
|
||||
if (self == context)
|
||||
{
|
||||
if (NSMapGet(_objectsByGID, globalID) == nil
|
||||
&& _sharedContext && [_sharedContext objectForGlobalID: globalID])
|
||||
{
|
||||
_flags.ignoreChangeNotification = NO;
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to initialize object contained in EOSharedEditingContext"];
|
||||
}
|
||||
objectStore = [(EOObjectStoreCoordinator*)_objectStore objectStoreForGlobalID: globalID];
|
||||
[objectStore initializeObject: object
|
||||
withGlobalID: globalID
|
||||
|
@ -3449,13 +3550,21 @@ modified state of the object.**/
|
|||
editingContext: (EOEditingContext *)context
|
||||
{
|
||||
//Near OK
|
||||
if (object)
|
||||
if (object && [EOFault isFault: object] == NO)
|
||||
{
|
||||
//call globalID isTemporary //ret NO
|
||||
if (self == context)//??
|
||||
{
|
||||
//NO: in EODatabaseConetxt [object clearProperties];
|
||||
|
||||
if (NSMapGet(_objectsByGID, globalID) == nil
|
||||
&& _sharedContext
|
||||
&& [_sharedContext objectForGlobalID: globalID])
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Attempt to initialize object contained in EOSharedEditingContext"];
|
||||
}
|
||||
|
||||
//OK
|
||||
[_objectStore refaultObject: object
|
||||
withGlobalID: globalID
|
||||
|
@ -3620,6 +3729,55 @@ modified state of the object.**/
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)_processInitializedObjectsInSharedContext:(NSDictionary *)userInfo
|
||||
{
|
||||
NSArray *localGIDs = NSAllMapTableKeys(_objectsByGID);
|
||||
NSArray *newGIDs = [userInfo objectForKey:@"initialized"];
|
||||
if ([localGIDs count] && [newGIDs count])
|
||||
{
|
||||
NSSet *localSet = [NSSet setWithArray: localGIDs];
|
||||
NSSet *newSet = [NSSet setWithArray: newGIDs];
|
||||
if ([localSet intersectsSet: newSet])
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"An EOSharedEditingContext attempted to register an object which is already with an EOEditingContext"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is invoked when the default EOSharedEditingContext is
|
||||
* initilized. This causes all EOEditingConexts which are not
|
||||
* ignoring shared context notifications and do not contain any
|
||||
* registered objects to register the default shared context as
|
||||
* their shared context.
|
||||
*/
|
||||
- (void)_defaultEditingContextNowInitialized:(NSDictionary *)userInfo
|
||||
{
|
||||
if (_flags.ignoreSharedContextNotifications) return;
|
||||
if ([[self registeredObjects] count] == 0)
|
||||
{
|
||||
EOSharedEditingContext *sc
|
||||
= [EOSharedEditingContext _defaultSharedEditingContext];
|
||||
[self setSharedEditingContext: sc];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
removeObserver: self
|
||||
name: EODefaultSharedEditingContextWasInitializedNotification
|
||||
object: nil];
|
||||
}
|
||||
|
||||
- (void)_objectsInitializedInSharedContext:(NSNotification *)notification
|
||||
{
|
||||
[self _sendOrEnqueueNotification: notification
|
||||
selector: @selector(_processInitializedObjectsInSharedContext:)];
|
||||
}
|
||||
- (void)_defaultSharedEditingContextWasInitialized:(NSNotification *)notification
|
||||
{
|
||||
[self _sendOrEnqueueNotification: notification
|
||||
selector: @selector(_defaultEditingContextNowInitialized:)];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
@ -3866,7 +4024,6 @@ static BOOL usesContextRelativeEncoding = NO;
|
|||
{
|
||||
[self notImplemented: _cmd]; //TODO
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSObject (DeallocHack)
|
||||
|
@ -3903,4 +4060,5 @@ static BOOL usesContextRelativeEncoding = NO;
|
|||
|
||||
NSHashInsert(assocDeallocHT, object);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
104
EOControl/EOSharedEditingContext.h
Normal file
104
EOControl/EOSharedEditingContext.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* -*-objc-*-
|
||||
EOSharedEditingContext.h
|
||||
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
Author: David Ayers <d.ayers@inode.at>
|
||||
Date: November 2005
|
||||
|
||||
This file is part of the GNUstep Database Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __EOSharedEditingContext_h__
|
||||
#define __EOSharedEditingContext_h__
|
||||
|
||||
#include <EOControl/EOEditingContext.h>
|
||||
#include <EOControl/EODefines.h>
|
||||
|
||||
@class NSString;
|
||||
@class NSArray;
|
||||
@class NSMutableArray;
|
||||
@class NSDictionary;
|
||||
@class NSMutableDictionary;
|
||||
@class NSUndoManager;
|
||||
@class EOMultiReaderLock;
|
||||
@class EOFetchSpecification;
|
||||
@class EOGlobalID;
|
||||
|
||||
GDL2CONTROL_EXPORT
|
||||
NSString *EODefaultSharedEditingContextWasInitializedNotification;
|
||||
|
||||
GDL2CONTROL_EXPORT
|
||||
NSString *EOSharedEditingContextInitializedObjectsNotification;
|
||||
|
||||
@interface EOSharedEditingContext : EOEditingContext
|
||||
{
|
||||
NSRecursiveLock *_sharedLock; /* FIXME: Use EOMultiReaderLock. */
|
||||
int _readerLockCount;
|
||||
int _readerLockCountSuspended;
|
||||
NSMutableArray *_initializedGlobalIDs;
|
||||
NSMutableDictionary *_objsByEntity;
|
||||
NSMutableDictionary *_objsByEntityFetchSpec;
|
||||
}
|
||||
|
||||
+ (EOSharedEditingContext *)defaultSharedEditingContext;
|
||||
+ (void)setDefaultSharedEditingContext: (EOSharedEditingContext *)context;
|
||||
|
||||
- (NSDictionary *)objectsByEntityName;
|
||||
- (NSDictionary *)objectsByEntityNameAndFetchSpecificationName;
|
||||
- (void)bindObjectsWithFetchSpecification: (EOFetchSpecification *)fetchSpec
|
||||
toName: (NSString *)name;
|
||||
|
||||
- (void)lockForReading;
|
||||
- (void)unlockForReading;
|
||||
- (BOOL)tryLockForReading;
|
||||
- (void)suspendReaderLocks;
|
||||
- (void)retrieveReaderLocks;
|
||||
|
||||
- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetchSpec
|
||||
editingContext: (EOEditingContext *)context;
|
||||
|
||||
- (EOSharedEditingContext *)sharedEditingContext;
|
||||
- (void)setSharedEditingContext: (EOSharedEditingContext *)sharedContext;
|
||||
|
||||
- (void)reset;
|
||||
- (void)setUndoManager: (NSUndoManager *)undoManager;
|
||||
|
||||
- (id)objectForGlobalID: (EOGlobalID *)globalID;
|
||||
- (id)faultForGlobalID: (EOGlobalID *)globalID
|
||||
editingContext: (EOEditingContext *)context;
|
||||
- (void)refaultObject: (id)object
|
||||
withGlobalID: (EOGlobalID *)globalID
|
||||
editingContext: (EOEditingContext *)context;
|
||||
|
||||
- (NSArray *)updatedObjects;
|
||||
- (NSArray *)insertedObjects;
|
||||
- (NSArray *)deletedObjects;
|
||||
|
||||
- (BOOL)hasChanges;
|
||||
- (void)validateChangesForSave;
|
||||
|
||||
- (NSArray *)registeredObjects;
|
||||
|
||||
- (void)objectWillChange: (id)object;
|
||||
- (void)insertObject: (id)object;
|
||||
- (void)deleteObject: (id)object;
|
||||
- (void)saveChanges;
|
||||
@end
|
||||
|
||||
#endif
|
704
EOControl/EOSharedEditingContext.m
Normal file
704
EOControl/EOSharedEditingContext.m
Normal file
|
@ -0,0 +1,704 @@
|
|||
/* -*-objc-*-
|
||||
EOSharedEditingContext.m
|
||||
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
Author: David Ayers <d.ayers@inode.at>
|
||||
Date: November 2005
|
||||
|
||||
This file is part of the GNUstep Database Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
RCS_ID("$Id$")
|
||||
|
||||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSCategories.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
#else
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSDictionary.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSNotification.h>
|
||||
#include <Foundation/NSSet.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#endif
|
||||
|
||||
#include <GNUstepBase/GSLock.h>
|
||||
|
||||
#include "EOSharedEditingContext.h"
|
||||
#include "EOFault.h"
|
||||
#include "EOFetchSpecification.h"
|
||||
#include "EOGlobalID.h"
|
||||
#include "EOObjectStoreCoordinator.h"
|
||||
#include "EOUndoManager.h"
|
||||
|
||||
|
||||
NSString *EODefaultSharedEditingContextWasInitializedNotification
|
||||
= @"EODefaultSharedEditingContextWasInitializedNotification";
|
||||
|
||||
NSString *EOSharedEditingContextInitializedObjectsNotification
|
||||
= @"EOSharedEditingContextInitializedObjectsNotification";
|
||||
|
||||
@interface EOEditingContext (Private)
|
||||
- (BOOL)_processRecentChanges;
|
||||
@end
|
||||
|
||||
/**
|
||||
* <p>Immutable Enterprise Objects can be shared among EOEditingContexts
|
||||
* via EOSharedEditingContext. Normally EOs belong to a specific
|
||||
* EOEditingContext and this editing context tracks the changes of this
|
||||
* object. Yet sometimes immutable objects are often referenced by many
|
||||
* objects and they would have to fetched and tracked within many
|
||||
* EOEditingContexts. EOSharedEditingContext is intended to address this
|
||||
* by supplying an shared context for immutable objects which can be shared
|
||||
* among instances of EOEditingContext. An EO that is registered with an
|
||||
* EOSharedEditingContext may not be contained in an other EOEditingContext
|
||||
* which uses the EOSharedEditingContext.</p>
|
||||
* <p>The only valid way to modify an
|
||||
* object that is contained in a shared context is by changing it in an
|
||||
* unreladed EOEditingContext (i.e. one which does not use the
|
||||
* EOSharedEditingContext), commit those changes to the object store which
|
||||
* would post a EOObjectsChangedInStoreNotification which in turn will
|
||||
* cause the EOSharedEditingContext to invalidate an subsequently refetch
|
||||
* the values of the EO from its object store.</p>
|
||||
* <p>Objects are fetched with [-objectsWithFetchSpecification:] or
|
||||
* [-bindObjectsWithFetchSpecification:toName:] into an EOSharedEditingContext.
|
||||
* If the later method is used, the objects can be later retrieved via
|
||||
* [-objectsByEntityNameAndFetchSpecificationName].</p>
|
||||
*/
|
||||
@implementation EOSharedEditingContext
|
||||
static NSArray *emptyArray = nil;
|
||||
static Class EOFaultClass = NULL;
|
||||
static NSRecursiveLock *llock = nil;
|
||||
+ (void)initialize
|
||||
{
|
||||
if (emptyArray==nil)
|
||||
{
|
||||
emptyArray = [NSArray new];
|
||||
EOFaultClass = [EOFault class];
|
||||
llock = [GSLazyRecursiveLock new];
|
||||
}
|
||||
}
|
||||
|
||||
static EOSharedEditingContext *dfltSharedEditingContext = nil;
|
||||
|
||||
/**
|
||||
* Returns the current default shared editing context.
|
||||
* This method will create one if none currently exists.
|
||||
* The first time this method implicitly creates a shared
|
||||
* editing context it will post a
|
||||
* <code>EODefaultSharedEditingContextWasInitializedNotification</code>.
|
||||
*/
|
||||
+ (EOSharedEditingContext *)defaultSharedEditingContext
|
||||
{
|
||||
[llock lock];
|
||||
|
||||
/* The reference implementatin seems to have a private
|
||||
dfltSharedEditingContext method which would be called here.
|
||||
Yet if the this method is not public for custom subclasses
|
||||
it doesn't seem to make sense to avoid the static variable directly. */
|
||||
if (!dfltSharedEditingContext)
|
||||
{
|
||||
static BOOL posted = NO;
|
||||
dfltSharedEditingContext = [[[self class] alloc] init];
|
||||
|
||||
if (!posted)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:
|
||||
EODefaultSharedEditingContextWasInitializedNotification
|
||||
object: nil];
|
||||
posted = YES;
|
||||
}
|
||||
}
|
||||
|
||||
[llock unlock];
|
||||
return dfltSharedEditingContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* This privat method is intended for EOEditingContext to
|
||||
* retrieve the default shared editing context without
|
||||
* creating one implicitly.
|
||||
* This seems to be broken by design as it breaks subclassing
|
||||
* of both EOEditingContext and EOSharedEditingContext.
|
||||
*/
|
||||
+ (EOSharedEditingContext *)_defaultSharedEditingContext
|
||||
{
|
||||
return dfltSharedEditingContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Explicity sets the default shared editing context.
|
||||
* If CONTEXT is not an EOSharedEditingContext this method raises an
|
||||
* NSInternalInconsistency exception.
|
||||
*/
|
||||
+ (void)setDefaultSharedEditingContext: (EOSharedEditingContext *)context
|
||||
{
|
||||
if (![context isKindOfClass: [EOEditingContext class]])
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"+[EOSharedEditingContext setDefaultSharedEditingContext:] attempted to set non-shared editing context as default shared editing context:%@",context];
|
||||
|
||||
}
|
||||
[llock lock];
|
||||
ASSIGN(dfltSharedEditingContext,context);
|
||||
[llock unlock];
|
||||
}
|
||||
|
||||
- (id)initWithParentObjectStore: (EOObjectStore *)parentObjectStore
|
||||
{
|
||||
if (![parentObjectStore isKindOfClass: [EOObjectStoreCoordinator class]])
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"EOSharedEditingContext must be initialized with an EOObjectStoreCoordinator"];
|
||||
}
|
||||
if ((self = [super initWithParentObjectStore: parentObjectStore]))
|
||||
{
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
_sharedLock = [GSLazyRecursiveLock new];
|
||||
_initializedGlobalIDs = [NSMutableArray new];
|
||||
_objsByEntity = [NSMutableDictionary new];
|
||||
_objsByEntityFetchSpec = [NSMutableDictionary new];
|
||||
|
||||
/* Now adjust EOEditingContext initializations. */
|
||||
_flags.retainsAllRegisteredObjects = YES;
|
||||
[super setSharedEditingContext: nil];
|
||||
[nc removeObserver: self
|
||||
name: NSUndoManagerCheckpointNotification
|
||||
object: nil];
|
||||
[nc removeObserver: self
|
||||
name: EOSharedEditingContextInitializedObjectsNotification
|
||||
object: nil];
|
||||
[nc removeObserver: self
|
||||
name: EOGlobalIDChangedNotification
|
||||
object: nil];
|
||||
|
||||
DESTROY(_undoManager);
|
||||
DESTROY(_lock);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
/* TODO Maybe we should add some sanity checks. */
|
||||
DESTROY(_sharedLock);
|
||||
DESTROY(_initializedGlobalIDs);
|
||||
DESTROY(_objsByEntity);
|
||||
DESTROY(_objsByEntityFetchSpec);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all object currently maintained the the EOSharedEditingContext
|
||||
* in an NSDictionary associated with the corresponding entity name.
|
||||
*/
|
||||
- (NSDictionary *)objectsByEntityName
|
||||
{
|
||||
NSDictionary *oben;
|
||||
[self lockForReading];
|
||||
NS_DURING
|
||||
{
|
||||
oben = AUTORELEASE([_objsByEntity copy]);
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlockForReading];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlockForReading];
|
||||
return oben;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all object currently maintained the the EOSharedEditingContext
|
||||
* in an NSDictionary associated with the corresponding name supplied by
|
||||
* previous [-bindObjectsWithFetchSpecification:toName:] each containing
|
||||
* a dictionary in which the objects are assicated with the entity name.
|
||||
*/
|
||||
- (NSDictionary *)objectsByEntityNameAndFetchSpecificationName
|
||||
{
|
||||
NSDictionary *oben;
|
||||
[self lockForReading];
|
||||
NS_DURING
|
||||
{
|
||||
oben = AUTORELEASE([_objsByEntityFetchSpec copy]);
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlockForReading];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlockForReading];
|
||||
return oben;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes [-objectsWithFetchSpecification:] and registers the objects
|
||||
* to be retrieved with [-objectsByEntityName] and
|
||||
* [-objectsByEntityNameAndFetchSpecificationName];
|
||||
*/
|
||||
- (void)bindObjectsWithFetchSpecification: (EOFetchSpecification *)fetchSpec
|
||||
toName: (NSString *)name
|
||||
{
|
||||
NSArray *objects;
|
||||
NSString *entityName;
|
||||
NSMutableDictionary *obefsn;
|
||||
|
||||
if (!name)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"called bindObjectsWithFetchSpecification:toName: without name"];
|
||||
}
|
||||
entityName = [fetchSpec entityName];
|
||||
|
||||
[self lock];
|
||||
NS_DURING
|
||||
{
|
||||
objects = [self objectsWithFetchSpecification: fetchSpec
|
||||
editingContext: self];
|
||||
obefsn = [_objsByEntityFetchSpec objectForKey: name];
|
||||
if (obefsn == nil)
|
||||
{
|
||||
obefsn = [NSMutableDictionary dictionaryWithObject: objects
|
||||
forKey: entityName];
|
||||
[_objsByEntityFetchSpec setObject: obefsn forKey: name];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Verify preliminary tests inidcate that previous
|
||||
fetch results get replaced, not merged. */
|
||||
[obefsn setObject: objects forKey: entityName];
|
||||
}
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
[self unlock];
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the recievers lock count for reading.
|
||||
*/
|
||||
- (void)lockForReading
|
||||
{
|
||||
/* FIXME: actually this blocks if another thread is reading.
|
||||
This should be fixed once we have EOMultiReaderLock. */
|
||||
[_sharedLock lock];
|
||||
_readerLockCount++;
|
||||
[_sharedLock unlock];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the recievers lock count for reading.
|
||||
*/
|
||||
- (void)unlockForReading
|
||||
{
|
||||
/* FIXME: actually this blocks if another thread is reading.
|
||||
This should be fixed once we have EOMultiReaderLock. */
|
||||
[_sharedLock lock];
|
||||
_readerLockCount--;
|
||||
[_sharedLock unlock];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to increases the recievers lock count for reading.
|
||||
* Returns NO if the lock cannot be retrieved.
|
||||
*/
|
||||
- (BOOL)tryLockForReading
|
||||
{
|
||||
BOOL flag;
|
||||
/* FIXME: actually this blocks if another thread is reading.
|
||||
This should be fixed once we have EOMultiReaderLock. */
|
||||
flag = [_sharedLock tryLock];
|
||||
if (flag)
|
||||
{
|
||||
_readerLockCount++;
|
||||
[_sharedLock unlock];
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspends the reader lock count until retrieveReaderLocks is called.
|
||||
*/
|
||||
- (void)suspendReaderLocks
|
||||
{
|
||||
[_sharedLock lock];
|
||||
_readerLockCountSuspended = _readerLockCount;
|
||||
_readerLockCount = 0;
|
||||
[_sharedLock unlock];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve suspended reader lock count.
|
||||
*/
|
||||
- (void)retrieveReaderLocks
|
||||
{
|
||||
[_sharedLock lock];
|
||||
_readerLockCount = _readerLockCountSuspended;
|
||||
_readerLockCountSuspended = 0;
|
||||
[_sharedLock unlock];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the objects with the FETCHSPEC and registers them
|
||||
* for retrieval with [-objectsByEntityName].
|
||||
*/
|
||||
- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetchSpec
|
||||
editingContext: (EOEditingContext *)context
|
||||
{
|
||||
NSArray *objs = [super objectsWithFetchSpecification: fetchSpec
|
||||
editingContext: context];
|
||||
NSString *entityName = [fetchSpec entityName];
|
||||
NSArray *obe = [_objsByEntity objectForKey: entityName];
|
||||
|
||||
if (obe == nil)
|
||||
{
|
||||
obe = AUTORELEASE([objs mutableCopy]);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableSet *set=[NSMutableSet setWithArray: obe];
|
||||
[set addObjectsFromArray: objs];
|
||||
obe = [set allObjects];
|
||||
}
|
||||
[_objsByEntity setObject: obe forKey: entityName];
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
/**
|
||||
* EOSharedEditingContexts cannot have shared editing contexts.
|
||||
* This methos allways returns nil.
|
||||
*/
|
||||
- (EOSharedEditingContext *)sharedEditingContext
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises an NSInternalInconsistencyException
|
||||
* unless SHAREDCONTEXT is nil.
|
||||
*/
|
||||
- (void)setSharedEditingContext: (EOSharedEditingContext *)sharedContext
|
||||
{
|
||||
if (sharedContext)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"+[%@ %@] illegal operation for in shared editing context", NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriden to do nothing.
|
||||
*/
|
||||
- (void)reset
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises an NSInternalInconsistencyException
|
||||
* unless SHAREDCONTEXT is nil.
|
||||
*/
|
||||
- (void)setUndoManager: (NSUndoManager *)undoManager
|
||||
{
|
||||
if (undoManager)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"+[%@ %@] illegal operation for in shared editing context", NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object of the superclass implementation but insures that
|
||||
* the returned object is valid in autoreleased in the current autorelease
|
||||
* pool of the calling thread.
|
||||
*/
|
||||
- (id)objectForGlobalID: (EOGlobalID *)globalID
|
||||
{
|
||||
id obj;
|
||||
[self lockForReading];
|
||||
NS_DURING
|
||||
{
|
||||
obj = AUTORELEASE(RETAIN([super objectForGlobalID: globalID]));
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlockForReading];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlockForReading];
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fault of the superclass implementation but insures that
|
||||
* the returned object is valid in autoreleased in the current autorelease
|
||||
* pool of the calling thread.
|
||||
*/
|
||||
- (id)faultForGlobalID: (EOGlobalID *)globalID
|
||||
editingContext: (EOEditingContext *)context
|
||||
{
|
||||
id obj;
|
||||
[self lockForReading];
|
||||
NS_DURING
|
||||
{
|
||||
obj = AUTORELEASE(RETAIN([super faultForGlobalID: globalID
|
||||
editingContext: context]));
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlockForReading];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlockForReading];
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked if the objects have been modified
|
||||
* in an unrelated EOEditingContext and therefor needs to
|
||||
* be invalidated and refetched here.
|
||||
*/
|
||||
- (void)refaultObject: (id)object
|
||||
withGlobalID: (EOGlobalID *)globalID
|
||||
editingContext: (EOEditingContext *)context
|
||||
{
|
||||
if (object && [EOFaultClass isFault: object] == NO)
|
||||
{
|
||||
[self lock];
|
||||
NS_DURING
|
||||
{
|
||||
[super refaultObject: object
|
||||
withGlobalID: globalID
|
||||
editingContext: context];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty array since a shared editing context
|
||||
* may not insert objects.
|
||||
*/
|
||||
- (NSArray *)updatedObjects
|
||||
{
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty array since a shared editing context
|
||||
* may not insert objects.
|
||||
*/
|
||||
- (NSArray *)insertedObjects
|
||||
{
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty array since a shared editing context
|
||||
* may not delete objects.
|
||||
*/
|
||||
- (NSArray *)deletedObjects
|
||||
{
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns NO since a shared editing context may not have changes.
|
||||
*/
|
||||
- (BOOL)hasChanges
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriden to do nothing.
|
||||
*/
|
||||
- (void)validateChangesForSave
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registered objects of the superclass implementation
|
||||
* but insures that that the returned objects are valid
|
||||
* in autoreleased in the current autorelease pool of the calling thread.
|
||||
*/
|
||||
- (NSArray *)registeredObjects
|
||||
{
|
||||
NSArray *objs;
|
||||
[self lockForReading];
|
||||
NS_DURING
|
||||
{
|
||||
objs = AUTORELEASE(RETAIN([super registeredObjects]));
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlockForReading];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlockForReading];
|
||||
return objs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises an NSInternalInconsistencyException
|
||||
* since objects in a shared editing context may not be modified.
|
||||
*/
|
||||
- (void)objectWillChange: (id)object;
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"+[%@ deleteObject:] attempted to delete object in shared editing context", [self class]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises an NSInternalInconsistencyException
|
||||
* since a shared editing context may not delete objects.
|
||||
*/
|
||||
- (void)insertObject: (id)object
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"+[%@ %@] illegal operation for in shared editing context", NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises an NSInternalInconsistencyException
|
||||
* since a shared editing context may not delete objects.
|
||||
*/
|
||||
- (void)deleteObject: (id)object
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"+[%@ %@] illegal operation for in shared editing context", NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises an NSInternalInconsistencyException
|
||||
* since objects in a shared editing context may not be modified.
|
||||
*/
|
||||
- (void)saveChanges
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"+[%@ %@] illegal operation for in shared editing context", NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
- (void)lock
|
||||
{
|
||||
unsigned int timeout=1024;
|
||||
[_sharedLock lock];
|
||||
while (_readerLockCount && timeout)
|
||||
{
|
||||
[_sharedLock unlock];
|
||||
timeout--;
|
||||
[_sharedLock lock];
|
||||
}
|
||||
if (timeout==0) NSLog(@"FIXME: ignoring lock to aviod deadlock!");
|
||||
[super lock];
|
||||
[_sharedLock unlock];
|
||||
}
|
||||
- (void)unlock
|
||||
{
|
||||
[_sharedLock lock];
|
||||
[super unlock];
|
||||
[_sharedLock unlock];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the super class implementation and recordes the object
|
||||
* for the next EOSharedEditingContextInitializedObjectsNotification
|
||||
* if the CONTEXT is the receiver which will be processed during
|
||||
* explicit or implicit processRecentChanges.
|
||||
*/
|
||||
- (void)initializeObject: (id)object
|
||||
withGlobalID: (EOGlobalID *)globalID
|
||||
editingContext: (EOEditingContext *)context
|
||||
{
|
||||
[self lock];
|
||||
NS_DURING
|
||||
{
|
||||
[super initializeObject: object
|
||||
withGlobalID: globalID
|
||||
editingContext: context];
|
||||
if (context == self)
|
||||
{
|
||||
[_initializedGlobalIDs addObject: globalID];
|
||||
}
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
}
|
||||
|
||||
/*
|
||||
* Overriding a private method indicates the mechanism is broken by design.
|
||||
* We need to need to notify obeserving EOEditingContexts of
|
||||
* objects which have been initialized.
|
||||
*/
|
||||
- (BOOL)_processRecentChanges
|
||||
{
|
||||
BOOL flag = NO;
|
||||
if ([_initializedGlobalIDs count])
|
||||
{
|
||||
NSDictionary *userInfo
|
||||
= [NSDictionary dictionaryWithObject: _initializedGlobalIDs
|
||||
forKey: @"initialized"];
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc postNotificationName: EOSharedEditingContextInitializedObjectsNotification
|
||||
object: self
|
||||
userInfo: userInfo];
|
||||
ASSIGN(_initializedGlobalIDs, [NSMutableArray arrayWithCapacity: 32]);
|
||||
}
|
||||
[self lock];
|
||||
NS_DURING
|
||||
{
|
||||
flag = [super _processRecentChanges];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[self unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
|
||||
return flag;
|
||||
}
|
||||
@end
|
|
@ -33,7 +33,6 @@
|
|||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
|
||||
@interface EOUndoManager : NSUndoManager
|
||||
|
||||
- (void)forgetAllWithTarget: (id)param0;
|
||||
|
|
|
@ -59,6 +59,7 @@ EOGlobalID.m \
|
|||
EOKeyGlobalID.m \
|
||||
EOObserver.m \
|
||||
EOEditingContext.m \
|
||||
EOSharedEditingContext.m \
|
||||
EODataSource.m \
|
||||
EODetailDataSource.m \
|
||||
EOUndoManager.m \
|
||||
|
@ -88,6 +89,7 @@ EOGlobalID.h \
|
|||
EOKeyGlobalID.h \
|
||||
EOObserver.h \
|
||||
EOEditingContext.h \
|
||||
EOSharedEditingContext.h \
|
||||
EODataSource.h \
|
||||
EODetailDataSource.h \
|
||||
EOArrayDataSource.h \
|
||||
|
|
Loading…
Reference in a new issue