/*! @header FTGraphVisitor @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.06.06 ola     initial version
  23.08.06 ola     license changed
  -------------------------------------------------------------------------
  
*/ #include #include #include #include #include #include #include @implementation FTGraphVisitor + (NSFileHandle *) createFile: (NSString *) filename { int fh; NSFileHandle *toReturn; fh = creat( [filename cString], O_CREAT | O_TRUNC | O_WRONLY ); fchmod( fh, S_IRWXU ); toReturn = [[[NSFileHandle alloc] initWithFileDescriptor: fh] autorelease]; return toReturn; } + (void) writeXMLHeaderIntoFile: (NSFileHandle *) fileHandle forGraphId: (NSString *) aGraphId hasToCreateGraph: (BOOL) toCreateGraph encoding: (int) anEncoding{ EC_AUTORELEASEPOOL_BEGIN NSMutableString *currentLine; currentLine = [[[NSMutableString alloc] init] autorelease]; [currentLine appendFormat: @"\n\n"]; #if 0 [currentLine appendFormat: @"\n\n"]; #endif [currentLine appendFormat: @"\n", aGraphId, (YES == toCreateGraph ) ? @"YES" : @"NO"]; [fileHandle writeData: [currentLine dataUsingEncoding: anEncoding]]; EC_AUTORELEASEPOOL_END } + (void) writeXMLFooterIntoFile: (NSFileHandle *) fileHandle encoding: (int) anEncoding { [fileHandle writeData: [@"\n" dataUsingEncoding: anEncoding]]; } - initForSession: (id ) aSession graphId: (id) aGraphId exportDirectory: (NSString *) dir baseFilename: (NSString *) baseFilename encoding: (int) anEncoding { self = [super init]; self->session = [aSession retain]; self->graphIdString = [aGraphId retain]; self->exportDir = [dir retain]; self->baseExportFilename = [baseFilename retain]; self->graph = nil; self->objectToIdMapper = nil; self->graphManager = nil; self->encoding = anEncoding; self->blobFileIdCounter = 0; return self; } - (void) dealloc { [self->session release]; [self->graphIdString release]; [self->exportDir release]; [self->baseExportFilename release]; [super dealloc]; } - exportContent { EC_AUTORELEASEPOOL_BEGIN id transaction; if( [[FTExport log] isTraceEnabled] ) { [[FTExport log] trace: @"FTGraphVisitor::exportContent"]; } self->objectToIdMapper = [self->session defaultObjectToIdMapper]; self->graphManager = [self->session graphManager]; if( [[FTExport log] isDebugEnabled] ) { [[FTExport log] debug: @"FTGraphVisitor::exportContent: Looking for graph "\ "with id=\"%@\"", self->graphIdString]; } transaction = [self->session beginTransactionWithParent: nil withSettings:nil]; self->graphId = [self->objectToIdMapper mapObject: self->graphIdString]; NS_DURING self->graph = [self->graphManager graphWithId: self->graphId]; NS_HANDLER [[FTExport log] error: @"FTGraphVisitor::exportContent: Unable to fetch graph with id="\ "\"%@\"", self->graphIdString]; [localException raise]; NS_ENDHANDLER if( [[FTExport log] isDebugEnabled] ) { [[FTExport log] debug: @"FTGraphVisitor::exportContent: Got graph!"]; } [[NSFileManager defaultManager] createDirectoryAtPath: [NSString stringWithFormat: @"%@/%@", self->exportDir, self->baseExportFilename] attributes: nil]; #if 1 [self exportGraphXml]; [self exportNodeIds]; #endif [self olacheck]; EC_AUTORELEASEPOOL_END return self; } - olacheck { id graphIdMapper; id nodeIterator; id transaction; graphIdMapper = [[graph objectToIdMapper] retain]; transaction = [self->session beginTransactionWithParent: nil withSettings: nil]; nodeIterator = [self->graph nodeIterator]; while( [nodeIterator hasNext] ) { id currentNode = [nodeIterator next]; id dictionary; id allKeys; dictionary = (id ) [currentNode serviceWithId: @"FTDictionaryService"]; allKeys = [dictionary allKeys]; } return self; } /* name of overall XML file */ #define __graph_xml_file "%@/%@/graph.xml" /* name of node id file: */ #define __node_ids_file "%@/%@/nodes.xml" #define __node_refs_file "%@/%@/references.xml" #define __node_blob_file "%@/%@/serviceData.xml" - exportGraphXml { EC_AUTORELEASEPOOL_BEGIN NSFileHandle *fileHandle; NS_DURING fileHandle = [FTGraphVisitor createFile: [NSString stringWithFormat: @__graph_xml_file, self->exportDir, self->baseExportFilename]]; NS_HANDLER [[FTExport log] error: @"FTGraphVisitor::exportGraphXML: Unable to create overall XML "\ "fragment. Exception: %@", localException]; [fileHandle closeFile]; [localException raise]; NS_ENDHANDLER NS_DURING [FTGraphVisitor writeXMLHeaderIntoFile: fileHandle forGraphId: self->graphIdString hasToCreateGraph: YES encoding: self->encoding]; [FTGraphVisitor writeXMLFooterIntoFile: fileHandle encoding: self->encoding]; NS_HANDLER [[FTExport log] error: @"FTGraphVisitor::exportGraphXML: Error while creating header. "\ "Exception: %@", localException]; [fileHandle closeFile]; [localException raise]; NS_ENDHANDLER [fileHandle closeFile]; EC_AUTORELEASEPOOL_END return self; } - exportNodeIds { EC_AUTORELEASEPOOL_BEGIN id nodeIterator; NSFileHandle *idsFileHandle, *refsFileHandle, *blobFileHandle; NS_DURING idsFileHandle = [FTGraphVisitor createFile: [NSString stringWithFormat: @__node_ids_file, self->exportDir, self->baseExportFilename]]; refsFileHandle = [FTGraphVisitor createFile: [NSString stringWithFormat: @__node_refs_file, self->exportDir, self->baseExportFilename]]; blobFileHandle = [FTGraphVisitor createFile: [NSString stringWithFormat: @__node_blob_file, self->exportDir, self->baseExportFilename]]; NS_HANDLER [[FTExport log] error: @"FTGraphVisitor::exportNodeIds: error creating file:"\ " "__node_ids_file" Exception: %@", localException]; [localException raise]; NS_ENDHANDLER [FTGraphVisitor writeXMLHeaderIntoFile: idsFileHandle forGraphId: self->graphIdString hasToCreateGraph: NO encoding: self->encoding]; [idsFileHandle writeData: [@" \n" dataUsingEncoding: self->encoding]]; [FTGraphVisitor writeXMLHeaderIntoFile: refsFileHandle forGraphId: self->graphIdString hasToCreateGraph: NO encoding: self->encoding]; [refsFileHandle writeData: [@" \n" dataUsingEncoding: self->encoding]]; [FTGraphVisitor writeXMLHeaderIntoFile: blobFileHandle forGraphId: self->graphIdString hasToCreateGraph: NO encoding: self->encoding]; [blobFileHandle writeData: [@" \n" dataUsingEncoding: self->encoding]]; NS_DURING id outgoingEdges; id graphIdMapper; graphIdMapper = [[graph objectToIdMapper] retain]; nodeIterator = [self->graph nodeIterator]; while( [nodeIterator hasNext] ) { NSMutableString *currentLine; id currentNode = [nodeIterator next]; currentLine = [[[NSMutableString alloc] initWithFormat: @" \n", [currentNode nodeId]] autorelease]; [idsFileHandle writeData: [currentLine dataUsingEncoding: self->encoding]]; /* determine outgoing nodes: */ currentLine = [[[NSMutableString alloc] initWithFormat: @" \n", [currentNode nodeId]] autorelease]; [refsFileHandle writeData: [currentLine dataUsingEncoding: self->encoding]]; outgoingEdges = [currentNode outgoingEdges]; while( [outgoingEdges hasNext] ) { id edge; edge = [outgoingEdges next]; currentLine = [[[NSMutableString alloc] initWithFormat: @" \n", [[edge targetNode] nodeId], [edge edgeId]] autorelease]; [refsFileHandle writeData: [currentLine dataUsingEncoding: self->encoding]]; } currentLine = [[[NSMutableString alloc] initWithFormat: @" \n"] autorelease]; [refsFileHandle writeData: [currentLine dataUsingEncoding: self->encoding]]; [self writeBlobEntriesOfNode: currentNode usingFileHandle: blobFileHandle]; } [idsFileHandle writeData: [@" \n" dataUsingEncoding: self->encoding]]; [FTGraphVisitor writeXMLFooterIntoFile: idsFileHandle encoding: self->encoding]; [refsFileHandle writeData: [@" \n" dataUsingEncoding: self->encoding]]; [FTGraphVisitor writeXMLFooterIntoFile: refsFileHandle encoding: self->encoding]; [blobFileHandle writeData: [@" \n" dataUsingEncoding: self->encoding]]; [FTGraphVisitor writeXMLFooterIntoFile: blobFileHandle encoding: self->encoding]; NS_HANDLER [[FTExport log] error: @"FTGraphVisitor::exportNodeIds: Got exception while iterating "\ "through all nodes. Exception message: %@", localException]; [localException raise]; NS_ENDHANDLER [idsFileHandle closeFile]; [refsFileHandle closeFile]; [blobFileHandle closeFile]; EC_AUTORELEASEPOOL_END return self; } - writeBlobEntriesOfNode: (id ) node usingFileHandle: (NSFileHandle *) fileHandle { EC_AUTORELEASEPOOL_BEGIN NSMutableString *currentLine; id keyIterator; id dictionaryService; currentLine = [NSMutableString stringWithFormat: @" \n", [node nodeId]]; [fileHandle writeData: [currentLine dataUsingEncoding: self->encoding]]; dictionaryService = (id ) [node serviceWithId: @"FTDictionaryService"]; keyIterator = [dictionaryService allKeys]; while( [keyIterator hasNext] ) { id key = [keyIterator next]; id value = [dictionaryService objectForKey: key]; if( [[FTExport log] isDebugEnabled] ) { [[FTExport log] debug: @"FTGraphVisitor::writeBlobEntriesOfNode: "\ "Got a key of dictionary service: %@", key]; } if( nil != key && nil != value ) { NSString *filename; filename = [self writeKey: key withValue: value]; [fileHandle writeData: [[NSString stringWithFormat: @" \n", filename ] dataUsingEncoding: self->encoding]]; } } [fileHandle writeData: [@" \n" dataUsingEncoding: self->encoding]]; EC_AUTORELEASEPOOL_END return self; } #define __blobdata_file @"%@/%@/blobdata-%u.obj" - (NSString *) writeKey: (id ) aKey withValue: (id ) value { NSString *filename; NSString *filenameEntry; NSMutableData *data; NSKeyedArchiver *archiver; /* todo: use a more space friendly approach here... */ filenameEntry = [[NSString alloc] initWithFormat: @"blobdata-%u.obj", ++(self->blobFileIdCounter)]; filename = [NSString stringWithFormat: @"%@/%@/%@", self->exportDir, self->baseExportFilename, filenameEntry ]; EC_AUTORELEASEPOOL_BEGIN data = [[[NSMutableData alloc] init] autorelease]; archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData: data] autorelease]; [archiver encodeObject: aKey forKey: @"key"]; [archiver encodeObject: value forKey: @"value"]; [archiver finishEncoding]; [data writeToFile: filename atomically: YES]; EC_AUTORELEASEPOOL_END return [filenameEntry autorelease]; } @end