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

  31.03.05 ola     initial version
  11.08.05 ola     simpler architecture through usage of FTOrderEdgeSet
  23.08.06 ola     license changed
  -------------------------------------------------------------------------
  
*/ #include #include #include #include #include #include #include #include #include #include @implementation FTNodeImpl - init { self = [super init]; self->graph = nil; self->nodeId = nil; self->lock = [[NSLock alloc] init]; self->incomingReferences = nil; self->outgoingReferences = nil; return self; } - initWithNodeId: (id ) anId forGraph: (FTGraphImpl *) aGraph { self = [self init]; self->nodeId = [anId retain]; self->graph = [aGraph retain]; self->incomingReferences = [[FTOrderedReferenceSetImpl alloc] initForBaseNode: self]; self->outgoingReferences = [[FTOrderedReferenceSetImpl alloc] initForBaseNode: self]; return self; } - (id) initWithCoder:(NSCoder *) decoder { id graphId = nil; FTSessionImpl *session; id correspondingGraph; self = [super initWithCoder: decoder]; self->lock = [[NSLock alloc] init]; NS_DURING graphId = [[decoder decodeObject] retain]; self->nodeId = [[decoder decodeObject] retain]; self->incomingReferences = [[decoder decodeObject] retain]; self->outgoingReferences = [[decoder decodeObject] retain]; NS_HANDLER if( nil != graphId ) { [graphId release]; graphId = nil; } [localException raise]; NS_ENDHANDLER /** * Now find out corresponding FTGraphImpl instance based on the retrieved id */ session = [FTSessionImpl currentSession]; NSAssert( nil != session, @"FTNodeImpl::initWithCoder: Unable to determine "\ "current session!" ); correspondingGraph = [[session graphManager] graphWithId: graphId]; NSAssert1( nil != correspondingGraph, @"FTNodeImpl::initWithCoder: Unable "\ "to fetch graph with id=\"%@\" for the previously loaded nodes!", graphId ); self->graph = (FTGraphImpl *) ([correspondingGraph retain]); return self; } - (void) dealloc { [self->lock release]; [self->incomingReferences release]; [self->outgoingReferences release]; [self->graph release]; [self->nodeId release]; [super dealloc]; } - addIncomingReferenceFromNodeId: (id ) aSourceNodeId withEdgeId: (id ) anEdgeId { [self->incomingReferences createAndAppendReferenceToNode: aSourceNodeId withEdgeId: anEdgeId]; [self internalStateChanged]; return self; } - addOutgoingReferenceToNodeId: (id ) aTargetNodeId withEdgeId: (id ) anEdgeId { [self->outgoingReferences createAndAppendReferenceToNode: aTargetNodeId withEdgeId: anEdgeId]; [self internalStateChanged]; return self; } - (unsigned) countIncomingReferences { return [self->incomingReferences countReferences]; } - (unsigned) countOutgoingReferences { return [self->outgoingReferences countReferences]; } - (id ) createAndAppendEdgeWithId: (id ) edgeId withTargetNode: (id ) targetNode { FTNodeImpl *target; FTEdgeImpl *edge = nil; if( nil == edgeId ) { [[[ECIllegalArgumentException alloc] initWithArgumentInfo: @"FTNodeImpl::createAndAppendEdgeWithId: Edge ID "\ "equals nil!" ] raise]; } if( nil == targetNode ) { [[[ECIllegalArgumentException alloc] initWithArgumentInfo: @"FTNodeImpl::createAndAppendEdgeWithId: Target "\ "node reference equals nil!" ] raise]; } if( ![targetNode isKindOfClass: [self class]] ) { [[[ECIllegalArgumentException alloc] initWithArgumentInfo: @"FTNodeImpl::createAndAppendEdgeWithId: Illegal "\ "target instance given!" ] raise]; } target = (FTNodeImpl *) targetNode; [target writeLock: YES]; [self writeLock: YES]; NS_DURING [self addOutgoingReferenceToNodeId: [targetNode nodeId] withEdgeId: edgeId]; [target addIncomingReferenceFromNodeId: [self nodeId] withEdgeId: edgeId]; edge = [[FTEdgeImpl alloc] initWithEdgeId: edgeId targetNode: targetNode sourceNode: self forGraph: self->graph ]; NS_HANDLER [target writeLock: NO]; [self writeLock: NO]; [localException raise]; NS_ENDHANDLER [self internalStateChanged]; [target writeLock: NO]; [self writeLock: NO]; return edge; } - (NSString *) description { NSString *desc = [[NSString alloc] initWithFormat: @"{id=%@}", [self->nodeId description]]; return desc; } - (void) encodeWithCoder: (NSCoder *) encoder { [encoder encodeObject: [self->graph graphId]]; [encoder encodeObject: self->nodeId]; [encoder encodeObject: self->incomingReferences]; [encoder encodeObject: self->outgoingReferences]; } - (id ) incomingEdges { id iterator; ECArrayIterator *result; NSMutableArray *edges; EC_AUTORELEASEPOOL_BEGIN iterator = [self->incomingReferences allReferences]; edges = [[[NSMutableArray alloc] init] autorelease]; while( [iterator hasNext] ) { id current = [iterator next]; FTEdgeImpl *edge = [[[FTEdgeImpl alloc] initWithEdgeId: [current edgeId] targetNode: self sourceNode: [self->graph nodeWithId: [current nodeId]] forGraph: self->graph] autorelease]; [edges addObject: edge]; } result = [[ECArrayIterator alloc] initWithArray: edges]; EC_AUTORELEASEPOOL_END return result; } - (id ) incomingNodes { return [self referencesToNodeIterator: self->incomingReferences]; } - internalStateChanged { [self->graph internalStateChanged: self]; return self; } /*! * @method nodeId * @result return the id of this node. */ - (id ) nodeId { return self->nodeId; } - (id ) outgoingEdges { id iterator; ECArrayIterator *result; NSMutableArray *edges; EC_AUTORELEASEPOOL_BEGIN iterator = [self->outgoingReferences allReferences]; edges = [[[NSMutableArray alloc] init] autorelease]; while( [iterator hasNext] ) { id current = [iterator next]; FTEdgeImpl *edge = [[[FTEdgeImpl alloc] initWithEdgeId: [current edgeId] targetNode: [self->graph nodeWithId: [current nodeId]] sourceNode: self forGraph: self->graph] autorelease]; [edges addObject: edge]; } result = [[ECArrayIterator alloc] initWithArray: edges]; EC_AUTORELEASEPOOL_END return result; } - (id ) outgoingNodes { return [self referencesToNodeIterator: self->outgoingReferences]; } - (id ) referencesToNodeIterator: (id ) references { id iterator; NSMutableArray *nodes; ECArrayIterator *result; EC_AUTORELEASEPOOL_BEGIN iterator = [references allReferences]; nodes = [[[NSMutableArray alloc] init] autorelease]; while( [iterator hasNext] ) { id current = [iterator next]; id outgoingNode = nil; NS_DURING outgoingNode = [self->graph nodeWithId: [current nodeId]]; [nodes addObject: outgoingNode]; NS_HANDLER NS_ENDHANDLER } result = [[ECArrayIterator alloc] initWithArray: nodes]; EC_AUTORELEASEPOOL_END return result; } - removeIncomingReferencePointingFrom: (FTNodeImpl *) sourceNode withEdgeId: (id ) edgeId { [self removeFromReferenceSet: self->incomingReferences node: sourceNode withEdgeId: edgeId ]; [self internalStateChanged]; return self; } - removeOutgoingReferencePointingTo: (FTNodeImpl *) targetNode withEdgeId: (id ) edgeId { [self removeFromReferenceSet: self->outgoingReferences node: targetNode withEdgeId: edgeId ]; [self internalStateChanged]; return self; } - removeFromReferenceSet: (id ) references node: (FTNodeImpl *) aNode withEdgeId: (id ) anEdgeId { id reference; reference = [references referenceByEdgeId: anEdgeId]; if( nil == reference ) { ECIllegalArgumentException *ex; NSString *msg; msg = [[NSString alloc] initWithFormat: @"FTNodeImpl::removeFromReferences:"\ " Unable to find in references %@ from node: %@", reference, aNode ]; ex = [[ECIllegalArgumentException alloc] initWithArgumentInfo: msg ]; [msg release]; [ex raise]; } if( ![[reference nodeId] isEqual: [aNode nodeId]] ) { ECIllegalStateException *ex; NSString *msg; msg = [[NSString alloc] initWithFormat: @"FTNodeImpl::removeFromReferences: node id of "\ "reference %@ does not contain node %@", reference, aNode]; ex = [[ECIllegalStateException alloc] initWithIllegalStateInfo: msg]; [msg release]; [ex raise]; } [references removeReference: reference]; return self; } - removeAllOutgoingNodesWithId: (id ) aNodeId { id referencesToRemove; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; referencesToRemove = [self->outgoingReferences referencesByNodeId: aNodeId]; [referencesToRemove autorelease]; if( nil != referencesToRemove ) { while( [referencesToRemove hasNext] ) { id current = [referencesToRemove next]; FTNodeImpl *targetNode; // fetch related target node NS_DURING targetNode = (FTNodeImpl *) [self->graph nodeWithId: [current nodeId]]; NS_HANDLER NSString *msg; ECIllegalStateException *ex; msg = [[[NSString alloc] initWithFormat: @"FTNodeImpl::removeAllOutgoingNodesWithId: Unable to find "\ "node with id=%@ to which this node with id=%@ is pointing to!", [current nodeId], [self nodeId] ] autorelease]; ex = [[ECIllegalStateException alloc] initWithIllegalStateInfo: msg]; [pool release]; [ex raise]; NS_ENDHANDLER NS_DURING [targetNode removeIncomingReferencePointingFrom: self withEdgeId: [current edgeId]]; [self removeOutgoingReferencePointingTo: targetNode withEdgeId: [current edgeId]]; NS_HANDLER [[FTLogging coreLog] error: @"FTNodeImpl::removeAllOutgoingNodesWithId: Unable to remove "\ "reference to target node %@", targetNode ]; NS_ENDHANDLER } } [pool release]; return self; } - (id ) serviceWithId: (NSString *) aServiceId { return [self->graph serviceWithId: aServiceId forNode: self]; } - writeLock: (BOOL) enable { if( enable ) { [self->lock lock]; } else { [self->lock unlock]; } return self; } @end