Logo Search packages:      
Sourcecode: adun.app version File versions  Download package

ULFileSystemDatabaseBackend.m

/*
   Project: UL

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   Created: 2005-07-12 15:24:33 +0200 by michael johnston

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This application 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
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include "ULFramework/ULFileSystemDatabaseBackend.h"

@implementation ULFileSystemDatabaseBackend

-(void) _createIndex: (NSString*) indexName inDirectory: (NSString*) dir
{
      ULDatabaseIndex *tempIndex;

      if([[dir lastPathComponent] isEqual: @"Simulations"])
            tempIndex = [[ULDatabaseSimulationIndex alloc] 
                  initWithDirectory: dir];
      else
            tempIndex = [[ULDatabaseIndex alloc] initWithDirectory: dir];
      
      [NSKeyedArchiver archiveRootObject: tempIndex toFile: 
            [dir stringByAppendingPathComponent: indexName]];
      [tempIndex release];
}

- (void) _saveIndex: (ULDatabaseIndex*) index ofClass: (NSString*) className
{
      id file;
      NSKeyedArchiver* archiver;
      NSMutableData* data = [NSMutableData data];

      if([className isEqual: @"ULSystem"])
            file = [systemDir stringByAppendingPathComponent: @"SystemIndex"];
      else if([className isEqual: @"ULOptions"])
            file = [optionsDir stringByAppendingPathComponent: @"OptionsIndex"];
      else if([className isEqual: @"AdDataSet"])
            file = [dataSetDir stringByAppendingPathComponent: @"DataSetIndex"];
      else if([className isEqual: @"ULSimulation"])
            file = [simulationDir stringByAppendingPathComponent: @"SimulationIndex"];
      
      archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData: data];
      [archiver setOutputFormat: NSPropertyListXMLFormat_v1_0];
      [archiver encodeObject: index forKey: @"root"];
      [archiver finishEncoding];
      [data writeToFile: file atomically: NO];
      [archiver release];
}

- (id) _unarchiveIndexAtLocation: (NSString*) location
{
      id object;  

      if((object  = [NSKeyedUnarchiver unarchiveObjectWithFile: location]) == nil)
            [NSException raise: NSInvalidArgumentException 
                  format: @"Decoding error. Could not locate index %@", location];

      return object;
}     

- (void) _checkForDirectory: (NSString*) path withIndex: (NSString*) indexName
{
      BOOL isDir;
      NSFileManager* fileManager = [NSFileManager defaultManager];

      if(!([fileManager fileExistsAtPath: path isDirectory: &isDir] && isDir))
      {
            [fileManager createDirectoryAtPath: path
                  attributes: nil];
            [self _createIndex: indexName inDirectory: path];
            NSWarnLog(@"Database directory %@ was missing. Created it and the corresponding index",
                  path);
      }           
}

- (void) _checkDatabaseSubdirectories
{
      [self _checkForDirectory: systemDir withIndex: @"SystemIndex"];
      [self _checkForDirectory: optionsDir withIndex: @"OptionsIndex"];
      [self _checkForDirectory: dataSetDir withIndex: @"DataSetIndex"];
      [self _checkForDirectory: simulationDir withIndex: @"SimulationIndex"];
}

00101 - (void) _setWorkingEnvironment
{
      NSUserDefaults* userDefaults;

      databaseDir = [[ULIOManager appIOManager] databaseDir];
      [databaseDir retain];
      systemDir = [[databaseDir stringByAppendingPathComponent: @"Systems"] retain];
      optionsDir = [[databaseDir stringByAppendingPathComponent: @"Options"] retain];
      dataSetDir = [[databaseDir stringByAppendingPathComponent: @"DataSets"] retain];
      simulationDir = [[databaseDir stringByAppendingPathComponent: @"Simulations"] retain];

      //check all database subdirectories exist
      //create them if they dont along with their index

      [self _checkDatabaseSubdirectories];

      //unarchive all the database indexes and add them to the correct arrays

      systemIndex = [self _unarchiveIndexAtLocation: 
            [systemDir stringByAppendingPathComponent: @"SystemIndex"]];
      [systemIndex retain];
      optionsIndex = [self _unarchiveIndexAtLocation: 
            [optionsDir stringByAppendingPathComponent: @"OptionsIndex"]];
      [optionsIndex retain];
      dataSetIndex = [self _unarchiveIndexAtLocation: 
            [dataSetDir stringByAppendingPathComponent: @"DataSetIndex"]];
      [dataSetIndex retain];
      simulationIndex = [self _unarchiveIndexAtLocation: 
            [simulationDir stringByAppendingPathComponent: @"SimulationIndex"]];
      [simulationIndex retain];

      databaseIndexes = [NSMutableDictionary new];
      [databaseIndexes setObject: systemIndex forKey: @"ULSystem"];
      [databaseIndexes setObject: optionsIndex forKey: @"ULOptions"];
      [databaseIndexes setObject: dataSetIndex forKey: @"AdDataSet"];
      [databaseIndexes setObject: simulationIndex forKey: @"ULSimulation"];

      //check all the indexes are present - if they are missing reindex the
      //directories contents
      ///FIXME: implement this

      //set an autosave timer

      userDefaults = [NSUserDefaults standardUserDefaults];
      
      if([userDefaults boolForKey: @"Autosave"])
      {
            autosaveTimer = [NSTimer scheduledTimerWithTimeInterval: 
                                    [userDefaults floatForKey: @"AutosaveInterval"]
                              target: self
                              selector: @selector(autosaveIndexes:)
                              userInfo: nil
                              repeats: YES];    
      }
}

- (id) init
{
      if(self = [super init])
      {
            [self _setWorkingEnvironment];
            if((userName = NSUserName()) == nil)
                  userName = @"unknown";
            
            [userName retain];
            databaseName = [NSString stringWithFormat: @"%@@localhost", userName];
            [databaseName retain];
            contentInformation = [NSArray arrayWithObjects: 
                              [NSDictionary dictionaryWithObjectsAndKeys:
                                     @"ULSystem", @"ULObjectClassName",
                                     @"Systems", @"ULObjectDisplayName", nil],
                              [NSDictionary dictionaryWithObjectsAndKeys:
                                     @"ULOptions", @"ULObjectClassName",
                                     @"Options", @"ULObjectDisplayName", nil],
                              [NSDictionary dictionaryWithObjectsAndKeys:
                                     @"AdDataSet", @"ULObjectClassName",
                                     @"DataSets", @"ULObjectDisplayName", nil],
                              [NSDictionary dictionaryWithObjectsAndKeys:
                                     @"ULSimulation", @"ULObjectClassName",
                                     @"Simulations", @"ULObjectDisplayName", nil],
                              nil];
            [contentInformation retain];              
      }

      return self;
}

- (void) dealloc
{
      [userName release];
      [contentInformation release];
      [databaseName release];
      [autosaveTimer invalidate];
      [databaseDir release];
      [systemDir release];
      [optionsDir release];
      [dataSetDir release];
      [simulationDir release];
      [databaseIndexes release];
      [systemIndex release];
      [optionsIndex release];
      [dataSetIndex release];
      [simulationIndex release];
}

- (NSString*) clientName
{
      return [[databaseName retain] autorelease];
}

- (NSArray*) contentTypeInformationForSchema: (NSString*) schema
{
      return [[contentInformation copy] autorelease];
}

- (void) addObject: (id) object toSchema: (NSString*) schema
{
      id index;

      if([object isKindOfClass: [AdModelObject class]])
      {
            //add database metadata to the object

            [[[object dataDictionary] objectForKey: @"General Data"]
                  setObject: databaseName forKey: @"Database"];
            [[[object dataDictionary] objectForKey: @"General Data"]
                  setObject: @"Local" forKey: @"Schema"];
            index = [databaseIndexes objectForKey: NSStringFromClass([object class])];
            [index addObject: object];
            [self _saveIndex: index ofClass: NSStringFromClass([object class])]; 
            [[NSNotificationCenter defaultCenter]
                  postNotificationName: @"ULDatabaseBackendDidAddObjectNotification"
                  object: object];
      }
      else
            [NSException raise: NSInvalidArgumentException
                  format: @"Unable to add object %@ to database. Not a descendant of AdModelObject.",
                  object];
}

00241 - (BOOL) objectInDatabase: (id) object
{
      id index;
      
      if([object isKindOfClass: [AdModelObject class]])
      {
            index = [databaseIndexes objectForKey: NSStringFromClass([object class])];
            return [index objectInIndex: object];
      }
      else
            return NO;
}

- (void) updateMetadataForObject: (id) object inSchema: (NSString*) schema
{
      id index;

      index = [databaseIndexes objectForKey: NSStringFromClass([object class])];
      if(index != nil)
      {
            [index updateMetadataForObject: object];
            [self _saveIndex: index ofClass: NSStringFromClass([object class])]; 
            [[NSNotificationCenter defaultCenter]
                  postNotificationName: @"ULDatabaseInterfaceDidUpdateMetadataNotification"
                  object: object];
      }           
}

- (void) updateOutputReferencesForObject: (id) object
{
      id index;

      index = [databaseIndexes objectForKey: NSStringFromClass([object class])];
      if(index != nil)
      {
            [index updateOutputReferencesForObject: object];
            [self _saveIndex: index ofClass: NSStringFromClass([object class])]; 
            [[NSNotificationCenter defaultCenter]
                  postNotificationName: @"ULDatabaseInterfaceDidUpdateOutputReferencesNotification"
                  object: object];
      }           
}

- (void) removeOutputReferenceToObjectWithID: (NSString*) identOne 
            fromObjectWithID: (NSString*) identTwo
            ofClass: (id) className 
            inSchema: (NSString*) schema;
{

      id index;

      index = [databaseIndexes objectForKey: className];
      [index removeOutputReferenceToObjectWithId: identOne
            fromObjectWithId: identTwo];
      [self _saveIndex: index ofClass: className]; 
      [[NSNotificationCenter defaultCenter]
            postNotificationName: @"ULDatabaseInterfaceDidUpdateOutputReferencesNotification"
            object: nil];
}

- (void) removeObjectOfClass: (id) className 
            withID: (NSString*) ident 
            fromSchema: (NSString*) schema
{
      id index;

      index = [databaseIndexes objectForKey: className];
      if(index != nil)
      {
            [index removeObjectWithId: ident];
            [self _saveIndex: index ofClass: className]; 
      }     
}

- (void) removeObjectsOfClass: (id) className 
            withIDs: (NSArray*) idents
            fromSchema: (NSString*) schema
{
      id index; 

      index = [databaseIndexes objectForKey: className];
      if(index != nil)
      {
            [index removeObjectsWithIds: idents];
            [self _saveIndex: index ofClass: className]; 
      }     
}

00329 - (void) reindexAll
{
      NSWarnLog(@"Not implemented (%@)", NSStringFromSelector(_cmd));
}

- (id) unarchiveObjectWithID: (NSString*) ident 
      ofClass: (id) className
      fromSchema: (NSString*) schema
{
      id index, object;

      index = [databaseIndexes objectForKey: className];
      if(index == nil)
            return nil;

      object = [index unarchiveObjectWithId: ident]; 
      
      //add volatile metadata attribute "clientName" so we can identify later
      //which client the object belongs to
      [object setValue: [[databaseName copy] autorelease] 
            forVolatileMetadataKey: @"DatabaseClient"];

      return object;
}

- (void) saveIndexes
{
      NSEnumerator* indexEnum;
      id indexClass;

      indexEnum = [databaseIndexes keyEnumerator];
      while(indexClass = [indexEnum nextObject])
            [self _saveIndex: [databaseIndexes objectForKey: indexClass]
                  ofClass: indexClass];
}

- (void) saveDatabase
{
      [self saveIndexes];
}

- (void) autosaveIndexes: (id) info
{
      [self saveIndexes];
} 

- (NSArray*) availableObjectsOfClass: (id) className
            inSchema: (NSString*) schema;
{
      id index;

      index = [databaseIndexes objectForKey: className];
      return [index availableObjects];
}

- (NSDictionary*) metadataForObjectWithID: (NSString*) ident 
                  ofClass: (id) className
                  inSchema: (NSString*) schema
{
      id index;

      index = [databaseIndexes objectForKey: className];
      return [index metadataForObjectWithID: ident];
}

- (NSArray*) outputReferencesForObjectWithID: (NSString*) ident 
            ofClass: (id) className 
            inSchema: (NSString*) schema
{
      id index;

      index = [databaseIndexes objectForKey: className];
      return [index outputReferencesForObjectWithID: ident];
}

- (NSArray*) inputReferencesForObjectWithID: (NSString*) ident 
            ofClass: (id) className
            inSchema: (NSString*) schema
{
      id index;

      index = [databaseIndexes objectForKey: className];
      return [index inputReferencesForObjectWithID: ident];
}

- (id) createStorageForSimulation: (id) object
{
      NSString* path;

      path = [simulationDir stringByAppendingPathComponent:
                  [NSString stringWithFormat: @"%@_Data",
                        [object identification]]];

      return [[[ULFileSystemSimulationStorage alloc]
                  initStorageForSimulationAtPath: path] autorelease];
}

- (NSArray*) schemaInformation
{
      return [NSArray arrayWithObject: [NSDictionary dictionaryWithObjectsAndKeys:
            @"Local", @"ULSchemaName",
            @"Usage", @"ULSchemaPrivileges", 
            userName, @"ULDatabaseUserName",
            [NSNumber numberWithBool: YES], @"ULSchemaOwner",
            databaseName, @"ULDatabaseClientName", nil]];
}

- (NSString*) simulationDir
{
      return [[simulationDir retain] autorelease];
}

- (NSString*) templateDir
{
      return [[optionsDir retain] autorelease];
}

- (NSString*) systemDir
{
      return [[systemDir retain] autorelease];
}

- (NSString*) dataSetDir
{
      return [[dataSetDir retain] autorelease];
}

@end

Generated by  Doxygen 1.6.0   Back to index