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