/*!
@header FTGraphManagerImpl
@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
23.02.05 ola initial version
19.08.06 ola removeGraphWithId added
23.08.06 ola license changed
-------------------------------------------------------------------------
*/
#include
#include
#include
#include
#include
#include
@implementation FTGraphManagerImpl
- initForServer: (FTServerImpl *) theServer
withGraphIdToGraphDatabase: (BDBDatabase *) theDatabase {
self = [super init];
self->lock = [[NSLock alloc] init];
self->server = [theServer retain];
self->graphIdToGraphDatabase = [theDatabase retain];
self->graphIdToGraphCache = [[ECCache alloc] init];
return self;
}
- (void) dealloc {
[self->graphIdToGraphCache release];
[self->lock release];
[self->server release];
[self->graphIdToGraphDatabase release];
[super dealloc];
}
- (id ) allGraphIds {
id toReturn = nil;
EC_AUTORELEASEPOOL_BEGIN
NSMutableArray *graphIds = [[[NSMutableArray alloc] init] autorelease];
int i = 1;
while( 1 ) {
BDBDatabaseRecordNumber *recno
= [[[BDBDatabaseRecordNumber alloc]
initWithEntryNumber: i] autorelease];
BDBDatabaseEntry *value = [[[BDBDatabaseEntry alloc]
init] autorelease];
BDBOperationStatus operationStatus;
if( [[FTLogging coreLog] isDebugEnabled] ) {
[[FTLogging coreLog]
debug: @"FTGraphManagerImpl::allGraphIds: "\
"trying to access record nr: %d", i ];
}
operationStatus = [self->graphIdToGraphDatabase
getEntryWithTransaction:nil
recordNumber:recno data: value];
if( operationStatus != BDB_STATUS_SUCCESS ) {
if( BDB_STATUS_NOTFOUND != operationStatus ) {
[[FTLogging coreLog]
error: @"FTGraphManagerImpl::allGraphIds: Unable to get graph id "\
"stored at bdb database record nr=%d", i];
[[[FTInternalDatamanagementException alloc]
initWithOperationStatus: operationStatus]
raise];
}
break;
} else {
[graphIds addObject: [[value object] graphId]];
}
i++;
}
toReturn = [[ECArrayIterator alloc]
initWithArray: graphIds];
EC_AUTORELEASEPOOL_END
return [toReturn autorelease];
}
- (id ) createGraphWithId: (id ) graphId {
FTGraphImpl *toReturn = nil;
BDBOperationStatus operationStatus = BDB_STATUS_UNKNOWN;
[self->lock lock];
EC_AUTORELEASEPOOL_BEGIN
/* look in the cache first: */
toReturn = (FTGraphImpl *) [self->graphIdToGraphCache objectForKey: graphId
incrementRefCounter: YES];
if( nil == toReturn ) {
NS_DURING
toReturn = [self lookupGraphWithId: graphId];
if( nil != toReturn ) {
/*
* graph with the given id already exists, so:
*/
[[[ECIllegalArgumentException alloc]
initWithArgumentInfo: @"A graph with the same identifier already "\
"exits!" ] raise];
}
NS_DURING
BDBDatabaseEntry *key, *value;
key = [[[BDBDatabaseEntry alloc] initWithObject: graphId] autorelease];
toReturn = [[FTGraphImpl alloc] initForServer: self->server
graphManager: self withId: graphId ];
// create the graph database:
[toReturn setupDatabases];
value = [[[BDBDatabaseEntry alloc] initWithObject: toReturn]
autorelease];
operationStatus = [self->graphIdToGraphDatabase
putEntryWithTransaction: nil key: key value: value];
NS_HANDLER
if( [localException isKindOfClass: [BDBException class]] ) {
BDBException *e = (BDBException *) localException;
FTInternalDatamanagementException *exception =
[[FTInternalDatamanagementException alloc]
initWithBDBException: e ];
[exception setCause: e];
[exception raise];
} else {
[[[[FTUnknownException alloc] initWithContextInfo:
@"Fetching FTGraphManagerImpl::createGraphWithId: adding a graph "\
"instance to the database" exception: localException]
setCause: localException]
raise];
}
NS_ENDHANDLER
if( BDB_STATUS_SUCCESS != operationStatus ) {
[[[FTInternalDatamanagementException alloc]
initWithOperationStatus: operationStatus ] raise];
} else {
[self->graphIdToGraphCache addObject: toReturn forKey: graphId];
}
NS_HANDLER
[self->lock unlock];
[localException raise];
NS_ENDHANDLER
}
[self->lock unlock];
EC_AUTORELEASEPOOL_END
return toReturn;
}
- (id ) graphWithId: (id ) graphId {
FTGraphImpl *toReturn = nil;
EC_AUTORELEASEPOOL_BEGIN
[self->lock lock];
toReturn = (FTGraphImpl *) [self->graphIdToGraphCache
objectForKey: graphId
incrementRefCounter: YES];
if( nil == toReturn ) {
/**
* cache lookup without success
*/
NS_DURING
toReturn = [self lookupGraphWithId: graphId ];
if( nil != toReturn ) {
[toReturn mountDatabases];
[self->graphIdToGraphCache addObject: toReturn forKey: graphId];
}
NS_HANDLER
[self->lock unlock];
[localException raise];
NS_ENDHANDLER
} else {
/**
* instance found in cache. databases mounted?
*/
if( ![toReturn databasesMounted] ) {
NS_DURING
[toReturn mountDatabases];
NS_HANDLER
[[FTLogging coreLog]
error: @"FTGraphManagerImpl::graphWithId: Exception while mounting "\
"databases of graph instance..." ];
[toReturn release];
[self->lock unlock];
[localException raise];
NS_ENDHANDLER
}
}
/**
* TODO: What to do here if the graph instance is returned, a thread-switch
* occurs which releases this graph instance and the instance will be removed?
* In this case the caller of this method will receive an illegal reference
* before it is able to call a "retain".
*
* Solution: Call retain in this method
*/
[self->lock unlock];
EC_AUTORELEASEPOOL_END
return toReturn;
}
- (FTGraphImpl *) lookupGraphWithId: (id ) graphId {
FTGraphImpl *toReturn = nil;
EC_AUTORELEASEPOOL_BEGIN
BDBDatabaseEntry *key, *value;
BDBOperationStatus operationStatus = BDB_STATUS_UNKNOWN;
key = [[[BDBDatabaseEntry alloc] initWithObject: graphId] autorelease];
value = [[[BDBDatabaseEntry alloc] init] autorelease];
NS_DURING
operationStatus = [self->graphIdToGraphDatabase
getEntryWithTransaction: nil key: key data: value ];
NS_HANDLER
if( [localException isKindOfClass: [BDBException class]] ) {
BDBException *e = (BDBException *) localException;
FTInternalDatamanagementException *exception =
[[FTInternalDatamanagementException alloc]
initWithBDBException: e ];
[exception setCause: localException];
[exception raise];
} else {
// got unknown exception
[[[[FTUnknownException alloc] initWithContextInfo:
@"Fetching FTGraphManagerImpl::lookupGraphWithId: a graph from the "\
"database" exception: localException]
setCause: localException]
raise];
}
NS_ENDHANDLER
if( BDB_STATUS_SUCCESS == operationStatus ) {
// got datum
toReturn = (FTGraphImpl *) [[value object] retain];
[toReturn initAfterDecodeForServer: self->server graphManager: self];
}
EC_AUTORELEASEPOOL_END
return [toReturn autorelease];
}
- (void) releaseGraph: (FTGraphImpl *) item {
[self->graphIdToGraphCache decrementRefCounterForKey: [item graphId]];
}
- removeGraphWithId: (id ) graphId {
FTGraphImpl *graph;
BOOL successful = NO;
if( [[FTLogging coreLog] isTraceEnabled] ) {
[[FTLogging coreLog]
trace: @"FTGraphManagerImpl::removeGraphWithId: Remove graph with id="\
"%@", graphId];
}
graph = [self lookupGraphWithId: graphId];
successful = [graph remove];
[self->graphIdToGraphCache removeObjectForKey: graphId];
NS_DURING
BDBDatabaseEntry *key;
BDBOperationStatus operationStatus;
key = [[[BDBDatabaseEntry alloc] initWithObject: graphId] autorelease];
operationStatus = [self->graphIdToGraphDatabase
deleteEntryWithTransaction: nil
key: key];
if( BDB_STATUS_SUCCESS != operationStatus ) {
[[FTLogging coreLog]
error: @"FTGraphManagerImpl::removeGraphWithId: Unable to remove "\
"graphId=%@ from mapping database!", graphId ];
[[[FTGraphRemoveException alloc]
initWithGraphId: graphId
withReason:
[NSString stringWithFormat:
@"FTGraphManagerImpl::removeGraphWithId: Unable to remove "\
"graphId=%@ from mapping database!", graphId]]
raise];
}
NS_HANDLER
[[FTLogging coreLog]
error: @"FTGraphManagerImpl::removeGraphWithId: Unable to remove "\
"graphId=%@ from mapping database!", graphId ];
[localException raise];
NS_ENDHANDLER
if( NO == successful ) {
[[FTLogging coreLog]
fatal: @"FTGraphManagerImpl::removeGraphWithId: Removing graph with id="\
"%@ FAILED. No having an unkown state!"];
[[[FTGraphRemoveException alloc]
initWithGraphId: graphId
withReason: @"Removing the data failed. Potentially inconsistent state "\
"for this graph."]
raise];
} else {
if( [[FTLogging coreLog] isDebugEnabled] ) {
[[FTLogging coreLog]
debug: @"FTGraphManagerImpl::removeGraphWithId: Graph with id="\
"%@ removed", graphId];
}
}
return self;
}
@end