/*! @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