/*!
@header FTDictionaryServiceForGraphImpl
@abstract Module of FT
@availability OS X, GNUstep
@copyright 2004, 2005, 2006 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-------------------------------------------------------------------------
Modification history
16.07.06 ola initial version
23.08.06 ola license changed
-------------------------------------------------------------------------
*/
#include "FTDictionaryServiceForGraphImpl.h"
#include
#include
#include
@implementation FTDictionaryServiceForGraphImpl
- initForGraph: (id ) aGraph
serviceLoader: (FTDictionaryServiceLoader *) aServiceLoader {
self = [super init];
self->database = nil;
self->databaseIsOpen = NO;
self->serviceLoader = [aServiceLoader retain];
self->writeLock = [[NSLock alloc] init];
if( ![aGraph isKindOfClass: [FTGraphImpl class]] ) {
[[FTLogging coreLog]
error: @"FTDictionaryServiceForGraphImpl::initForGraph: Given graph is "\
"NOT kind of class FTGraphImpl... Graph: %@", aGraph];
[[[ECIllegalStateException alloc]
initWithIllegalStateInfo:
[NSString stringWithFormat:
@"FTDictionaryServiceForGraphImpl::initForGraph: Given graph is "\
"NOT kind of class FTGraphImpl... Graph: %@", aGraph]]
raise];
}
[self openDatabaseForGraph: (FTGraphImpl *) aGraph
usingDatabaseName: [aServiceLoader databaseNameScheme]];
return self;
}
- (void) dealloc {
[self close];
[self->serviceLoader release];
[self->writeLock release];
[super dealloc];
}
- (void) close {
[self->writeLock lock];
NS_DURING
if( YES == self->databaseIsOpen ) {
if( nil != self->database ) {
[self->database close];
[self->database release];
self->database = nil;
}
self->databaseIsOpen = NO;
} else {
[self->database release];
}
NS_HANDLER
[self->writeLock unlock];
[localException raise];
NS_ENDHANDLER
[self->writeLock unlock];
}
- (BOOL) isOpen {
return self->databaseIsOpen;
}
- addDatabaseEntry: (BDBDatabaseEntry *) anEntry
forDatabaseKey: (BDBDatabaseEntry *) aKey {
BDBOperationStatus status = BDB_STATUS_UNKNOWN;
NS_DURING
status = [self->database
putEntryWithTransaction: nil
key: aKey
value: anEntry];
if( BDB_STATUS_SUCCESS != status ) {
[[[FTDatabaseUpdateException alloc]
initWithOperationStatus: status
operationInformation: @"FTDictionaryServiceForGraphImpl::"\
"addDatabaseEntry: Error while updating the BDB database"]
raise];
}
NS_HANDLER
FTDatabaseUpdateException *ex;
[[FTLogging coreLog]
error: @"FTDictionaryServiceForGraphImpl::addDatabaseEntry: Error while "\
"updating the BDB database"];
if( ![localException isKindOfClass: [FTDatabaseUpdateException class]] ) {
ex = [[FTDatabaseUpdateException alloc]
initWithOperationStatus: status
operationInformation: @"FTDictionaryServiceForGraphImpl::"\
"addDatabaseEntry: Error while updating the BDB database"];
[ex setCause: localException];
} else {
ex = (FTDatabaseUpdateException *) localException;
}
[ex raise];
NS_ENDHANDLER
return self;
}
- addObject: (id ) anObject forKey: (id ) aKey
forNode: (id ) aNode {
BDBDatabaseEntry *dbKey, *dbValue;
_FTDictionaryServiceKeysOfNode *keysOfNode = nil;
if( [[FTLogging coreLog] isTraceEnabled] ) {
[[FTLogging coreLog]
trace: @"FTDictionaryServiceForGraphImpl::addObject: forKey=\"%@\""\
" forNodeId=\"%@\"", aKey, [aNode nodeId]];
}
[self->writeLock lock];
NS_DURING
/* add the data: */
dbKey = [self
createDatabaseEntryKeyForNodeId: [aNode nodeId]
forKey: aKey];
dbValue = [[[BDBDatabaseEntry alloc] initWithObject: anObject] autorelease];
[self addDatabaseEntry: dbValue forDatabaseKey: dbKey];
/* now add the key itself to the dictionary as well: */
keysOfNode = [[_FTDictionaryServiceKeysOfNode alloc]
initForNode: aNode
dictionaryServiceForGraph: self];
[keysOfNode addKey: aKey];
NS_HANDLER
[self->writeLock unlock];
[keysOfNode release];
[localException raise];
NS_ENDHANDLER
[keysOfNode release];
[self->writeLock unlock];
return self;
}
- (id ) allKeysOfNode: (id ) aNode {
_FTDictionaryServiceKeysOfNode *dictOfNode
= [[_FTDictionaryServiceKeysOfNode alloc]
initForNode: aNode
dictionaryServiceForGraph: self];
return [dictOfNode allKeys];
}
- (BDBDatabaseEntry *) createDatabaseEntryKeyForNodeId: (id ) aNodeId
forKey: (id ) aKey {
NSMutableData *keyData = [[[NSMutableData alloc] init] autorelease];
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc]
initForWritingWithMutableData: keyData]
autorelease];
[archiver encodeObject: aNodeId forKey: @"nodeId"];
[archiver encodeObject: aKey forKey: @"key"];
[archiver finishEncoding];
return [[[BDBDatabaseEntry alloc]
initWithData: keyData]
autorelease];
}
- (BDBDatabaseEntry *) databaseEntryForKey: (BDBDatabaseEntry *) aDBKey {
BDBDatabaseEntry *toReturn = [[[BDBDatabaseEntry alloc] init] autorelease];
BDBOperationStatus opStatus = BDB_STATUS_UNKNOWN;
NS_DURING
opStatus = [self->database
getEntryWithTransaction: nil
key: aDBKey
data:toReturn];
NS_HANDLER
[[FTLogging coreLog]
error: @"FTDictionaryServiceForGraphImpl::databaseEntryForKey: "\
"Operation failed due to exception: \"%@\". Key=%@",
localException, aDBKey];
[localException raise];
NS_ENDHANDLER
if( BDB_STATUS_SUCCESS != opStatus ) {
if( BDB_STATUS_NOTFOUND == opStatus ) {
/* entry not found -> return nil */
toReturn = nil;
} else {
[[[FTInternalDatamanagementException alloc]
initWithOperationStatus: opStatus]
raise];
}
}
return toReturn;
}
- objectForKey: (id ) aKey ofNode: (id ) aNode {
BDBDatabaseEntry *dbKey;
BDBDatabaseEntry *dbValue;
id toReturn;
if( [[FTLogging coreLog] isTraceEnabled] ) {
[[FTLogging coreLog]
trace: @"FTDictionaryServiceForGraphImpl::objectForKey"];
}
dbKey = [self
createDatabaseEntryKeyForNodeId: [aNode nodeId]
forKey: aKey];
dbValue = [self databaseEntryForKey: dbKey];
if( nil != dbValue ) {
toReturn = [dbValue object];
}
return toReturn;
}
- openDatabaseForGraph: (FTGraphImpl *) aGraph
usingDatabaseName: (NSString *) aDatabaseName {
NSString *databaseName;
BDBDatabaseConfig * dbConfig;
if( YES == self->databaseIsOpen ) {
if( nil != self->database ) {
[self->database close];
[self->database release];
}
}
databaseName = [NSString
stringWithFormat: @"%@/%@",
[aGraph graphDatabaseDirectory],
aDatabaseName];
dbConfig = [[[BDBDatabaseConfig alloc] init]
autorelease];
[dbConfig setDatabaseType: BDB_BTREE];
[dbConfig setBTreeRecordNumbering: NO];
[dbConfig setAllowDuplicates: NO];
/*
* Check wether a file databaseName already exists. If so, then simply
* use it as dictionary service db; otherwise create one:
*/
if( ![[NSFileManager defaultManager]
fileExistsAtPath: databaseName] ) {
[dbConfig setAllowCreate: YES];
}
self->database = [BDBDatabase
initWithFilename: databaseName
databaseName: nil
databaseConfig: dbConfig];
if( nil != self->database ) {
self->databaseIsOpen = YES;
}
return self;
}
- removeDatabaseEntryForKey: (BDBDatabaseEntry *) key {
[self->database deleteEntryWithTransaction: nil key: key];
return self;
}
- removeObjectForKey: (id ) aKey ofNode: (id ) aNode {
BDBDatabaseEntry *dbKey;
_FTDictionaryServiceKeysOfNode *servicesOfNode;
if( [[FTLogging coreLog] isTraceEnabled] ) {
[[FTLogging coreLog]
trace: @"FTDictionaryServiceForGraphImpl::removeObjectForKey" ];
}
dbKey = [self
createDatabaseEntryKeyForNodeId: [aNode nodeId]
forKey: aKey];
[self removeDatabaseEntryForKey: dbKey];
servicesOfNode = [[[_FTDictionaryServiceKeysOfNode alloc]
initForNode: aNode
dictionaryServiceForGraph: self] autorelease];
[servicesOfNode removeKey: aKey];
return self;
}
- (id ) serviceForNode: (id ) aNode {
return [[[FTDictionaryServiceForNodeImpl alloc]
initForDictionaryServiceForGraph: self
forNode: aNode] autorelease];
}
- (id ) serviceLoader {
return self->serviceLoader;
}
@end
/**
* Used as key in order to store keys per node
*/
#define _Key4NodeKey @"__nodeKey"
@implementation _FTDictionaryServiceKeysOfNode
- initForNode: (id ) aNode
dictionaryServiceForGraph: (FTDictionaryServiceForGraphImpl *) aDictService {
self = [super init];
self->node = [aNode retain];
self->dictionaryForGraph = [aDictService retain];
return self;
}
- (void) dealloc {
[self-> node release];
[self->dictionaryForGraph release];
[super dealloc];
}
- (id ) allKeys {
return [[[ECEnumeratorIterator alloc]
initWithEnumerator: [[self fetchKeys] objectEnumerator]]
autorelease];
}
- addKey: (id ) aKey {
NSMutableSet *allKeys = [self fetchKeys];
[allKeys addObject: aKey];
[self storeKeys: allKeys];
return self;
}
- (BDBDatabaseEntry *) dbKeyForAllkeys {
return [self->dictionaryForGraph
createDatabaseEntryKeyForNodeId: [self->node nodeId]
forKey: _Key4NodeKey];
}
- (NSMutableSet *) fetchKeys {
BDBDatabaseEntry *key;
BDBDatabaseEntry *entry;
NSMutableSet *toReturn;
key = [self dbKeyForAllkeys];
entry = [self->dictionaryForGraph
databaseEntryForKey: key];
if( nil == entry ) {
toReturn = [[[NSMutableSet alloc] init] autorelease];
} else {
toReturn = [entry object];
}
return toReturn;
}
- removeKey: (id ) aKey {
NSMutableSet *allKeys = [self fetchKeys];
if( [allKeys containsObject: aKey] ) {
[allKeys removeObject: aKey];
[self storeKeys: allKeys];
}
return self;
}
- storeKeys: (NSMutableSet *) allKeys {
BDBDatabaseEntry *key = [self dbKeyForAllkeys];
BDBDatabaseEntry *value;
[self->dictionaryForGraph removeDatabaseEntryForKey: key];
value = [[[BDBDatabaseEntry alloc] initWithObject: allKeys] autorelease];
[self->dictionaryForGraph addDatabaseEntry: value forDatabaseKey: key];
return self;
}
@end