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

ULAnalysisManager.m

/*
   Project: UL

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

   Author: Michael Johnston

   Created: 2005-12-09 14:47:28 +0100 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/ULAnalysisManager.h"

@implementation ULAnalysisManager

- (Class) _loadBundle: (NSString*) pluginName fromDir: (NSString*) dir 
{
      NSBundle *pluginBundle;
      NSString *pluginPath;
      NSString *temp;
      Class pluginClass;

      NSDebugLLog(@"ULAnalysisManager", @"Plugin dir is %@. Plugin Name is %@", 
            dir, 
            pluginName);

      //add check to see if bundle actually exists

      pluginBundle = [NSBundle bundleWithPath: 
                        [dir stringByAppendingPathComponent: 
                        pluginName]];
      if(pluginBundle == nil)
            [NSException raise: NSInvalidArgumentException format: @"Specified plugin does not exist"];     

      NSDebugLLog(@"ULAnalysisManager", @"Plugin Bundle is %@", pluginBundle);
      NSDebugLLog(@"ULAnalysisManager", 
            @"Dynamicaly Loading Plugin (if neccessary) from Directory: %@.\n\n",
            [pluginBundle bundlePath]);

      if(pluginClass = [pluginBundle principalClass])
            NSDebugLLog(@"ULAnalysisManager", @"Found plugin (plugin=%@).\n",
                   [pluginClass description]);
      else
            [NSException raise: NSInternalInconsistencyException 
                  format: @"Specified plugin has no principal class"];

      NSDebugLLog(@"ULAnalysisManager", @"Loaded plugin\n");

      return pluginClass;
}

- (void) _setCurrentPlugin: (NSString*) name
{
      Class pluginClass;
      id holder;
      
      //check if this is the current plugin

      if(![name isEqual: currentPluginName])
      {
            //get the principal class of the plugin   

            pluginClass = [self _loadBundle: name fromDir: pluginDir];        
            holder = [pluginClass new];
            [currentPlugin release];
            currentPlugin = holder;
            [currentPluginName release];
            currentPluginName = [name retain];

            if(![currentPlugin conformsToProtocol:@protocol(ULAnalysisPlugin)])
            {
                  [currentPlugin release];
                  [currentPluginName release];
                  currentPluginName = nil;
                  currentPlugin = nil;
                  NSWarnLog(@"Plugin doesnt not conform to ULAnalysisPlugin protocol");
                  [NSException raise: NSInternalInconsistencyException 
                        format: @"Specified plugins (%@) principal class does not conform to ULAnalysisPlugin protocol", 
                        [pluginClass description]];
            }
      }
}

- (void) _findAvailablePlugins
{
      BOOL isDir;
      NSFileManager *fileManager = [NSFileManager defaultManager];
      NSEnumerator *pluginDirEnum;
      NSString *contentObject, *path;
      NSDictionary * inputInfo, *infoDict;
      NSBundle* bundle;

      //scan the analysis plugins directory and get all the bundle names

      pluginDirEnum = [[fileManager directoryContentsAtPath: pluginDir]
                        objectEnumerator];
      availablePlugins = [NSMutableArray new];
      pluginInfoDict = [NSMutableDictionary new];
      while(contentObject = [pluginDirEnum nextObject])
      {
            path = [pluginDir stringByAppendingPathComponent: contentObject];
            [fileManager fileExistsAtPath: path isDirectory: &isDir];
            if(isDir)
            {
                  //retrieve the info dict
                  bundle = [NSBundle bundleWithPath: path];
                  infoDict = [bundle infoDictionary];
                  inputInfo = [infoDict objectForKey: @"ULAnalysisPluginInputInformation"];
                  if(infoDict == nil)
                  {
                        NSWarnLog(@"Plugin %@ contains no Info.plist", contentObject);
                  }     
                  else if(inputInfo == nil)
                  {
                        NSWarnLog(@"%@ plugin Info.plist contains no input object information"
                                    ,contentObject);
                  }
                  else
                  {
                        [availablePlugins addObject: contentObject];
                        [pluginInfoDict setObject: inputInfo
                              forKey: contentObject];
                  }           
            }     
      }           

      NSDebugLLog(@"ULAnalysisManager", @"Available plugins %@", availablePlugins);
      NSDebugLLog(@"ULAnalysisManager", @"Plugin information %@", pluginInfoDict);
}

- (id) init
{
      id defaults;

      if((self = [super init]) != nil)
      {
            currentPluginName = nil;
            results = nil;
            pluginDir = [NSHomeDirectory() stringByAppendingPathComponent: @"adun/Plugins/Analysis"];
            [pluginDir retain];
            inputObjects = [NSMutableArray new];
            objectsCountDict = [NSMutableDictionary new];
            outputObjectsReferences = [NSMutableArray new];
            //Locate what plugins are available along with their input requirements.
            [self _findAvailablePlugins];
      }

      return self;
}

- (void) dealloc
{
      [results release];
      [outputObjectsReferences release];
      [availablePlugins release];
      [pluginInfoDict release];
      [pluginDir release];
      [inputObjects release];
      [objectsCountDict release];
      [currentPluginName release];
      [currentPlugin release];
}

//FIXME: This method needs to be updated
//Need to implement ULSimulations loadData
//so it can be called multiple times
/*
- (void) reloadResultsAtPath: (NSString*) path
{
      id holder;

      //FIXME: Ideally we should have more rigourous checking that
      //new energies/dynamics have actually been output since the
      //last time they were read in - A method in ULResults?

      holder = [[ULSimulation alloc] initWithTrajectoryAtPath: path];
      [currentResults release];
      currentResults = holder;
      
}*/

00195 - (id) applyPlugin: (NSString*) name withOptions: (NSMutableDictionary*) options
{
      NSEnumerator *inputObjectsEnum, *dataSetsEnum;
      id dataSet, inputObject;
      NSArray* dataSets;
      
      [self _setCurrentPlugin: name];
      [results release];
      [outputObjectsReferences removeAllObjects];

      NS_DURING
      {
            results = [currentPlugin processInputs: inputObjects
                        userOptions: options];
            [results retain];       
            dataSets = [results objectForKey: @"ULAnalysisPluginDataSets"];

            //set input references 
            //note: output references cant be added until the object is saved 
            //to a database.
            inputObjectsEnum = [inputObjects objectEnumerator];
            while(inputObject = [inputObjectsEnum nextObject])
            {
                  //FIXME: Unable to add input references for moltalk structures.
                  if([inputObject isKindOfClass: [AdModelObject class]])
                  {
                        //loop over every data set returned
                        dataSetsEnum = [dataSets objectEnumerator];
                        while(dataSet = [dataSetsEnum nextObject])
                        {
                              [dataSet addInputReferenceToObject: inputObject];
                              NSDebugMLLog(@"ULAnalysisManager", @"Data set input references %@", 
                                    [dataSet inputReferences]);
                        }     
                  }
            }     

            //Keep track of the objects that generated these data sets.
            [outputObjectsReferences  addObjectsFromArray: inputObjects];
      }
      NS_HANDLER
      {
            results  = nil;
            NSWarnLog(@"Results analysis failed due to an exception");
            NSWarnLog(@"%@ %@ %@", [localException name], 
                  [localException reason], 
                  [localException userInfo]);
            [localException raise];
      }
      NS_ENDHANDLER

      NSDebugLLog(@"ULAnalysisManager", @"Completed analysis. Returning %@", results);

      return results;
}

00251 - (void) saveOutputDataSet: (AdDataSet*) dataSet
{
      NSArray* dataSets;
      NSEnumerator* inputsEnum;
      id input;

      //check this object is one of the current output objects

      dataSets = [results objectForKey: @"ULAnalysisPluginDataSets"];
      if(![dataSets containsObject: dataSet])
            [NSException raise: NSInvalidArgumentException
                  format: @"Dataset is not among the current outputs"];

      [[ULDatabaseInterface databaseInterface]
            addObjectToFileSystemDatabase: dataSet];

      //Go through all the objects that created this dataSet and 
      //add an output reference to each
      inputsEnum = [outputObjectsReferences objectEnumerator];
      while(input = [inputsEnum nextObject])
      {
            if([input isKindOfClass: [AdModelObject class]])
            {
                  [input addOutputReferenceToObject: dataSet];
                  [[ULDatabaseInterface databaseInterface]
                        updateOutputReferencesForObject: input];
            }           
      }
}

00281 - (id) optionsForPlugin: (NSString*) name
{
      [self _setCurrentPlugin: name];     
      //FIXME
      return [currentPlugin pluginOptions: inputObjects];
}

00288 - (void) addInputObject: (id) object
{
      NSNumber* objectsCount;
      NSString* type;

      [inputObjects addObject: object];
      type = NSStringFromClass([object class]);
      if((objectsCount = [objectsCountDict objectForKey: type]) != nil)
      {     
            objectsCount = [NSNumber numberWithInt: 
                        [objectsCount intValue] +1];
            [objectsCountDict setValue: objectsCount forKey: type];
      }
      else
            [objectsCountDict setValue: [NSNumber numberWithInt: 1]     
                  forKey: type];
}

00306 - (void) removeInputObject: (id) object
{
      NSNumber* objectsCount;
      NSString* type;

      if(![inputObjects containsObject: object])
            return

      [inputObjects removeObject: object];
      type = NSStringFromClass([object class]);
      objectsCount = [objectsCountDict objectForKey: type];
      if([objectsCount intValue] == 1)
            [objectsCountDict removeObjectForKey: type];
      else
      {     
            objectsCount = [NSNumber numberWithInt: 
                        [objectsCount intValue] -1];
            [objectsCountDict setValue: objectsCount forKey: type];
      }
}

00327 - (void) removeAllInputObjects
{
      [inputObjects removeAllObjects];
      [objectsCountDict removeAllObjects];
}

- (NSArray*) inputObjects
{
      return [[inputObjects copy] autorelease];
}

00338 - (BOOL) containsInputObjects
{
      if([inputObjects count] != 0)
            return YES;
      else
            return NO;
}

00346 - (int) countOfInputObjectsOfClass: (NSString*) className
{
      NSNumber* count;

      count = [objectsCountDict objectForKey: className];
      if(count != nil)
            return [count intValue];
      else
            return 0;
}

- (BOOL) _pluginCanProcessCurrentInputs: (NSString*) pluginName
{
      NSNumber* number, *minimumNumber, *maximumNumber;
      NSArray* pluginInputs;
      NSMutableArray *inputTypes;
      NSEnumerator *inputsEnum;
      id input, inputType;

      pluginInputs = [pluginInfoDict objectForKey: pluginName];

      //Create an array containing the input types which are present
      //We will check this against the types the plugin can handle.
      //The plugin must be able to accept all these types

      inputTypes = [NSMutableArray array];
      inputsEnum = [objectsCountDict keyEnumerator];
      while(input = [inputsEnum nextObject])
            if([[objectsCountDict objectForKey: input] intValue] >0)
                  [inputTypes addObject: input];

      NSDebugLLog(@"ULAnalysisManager", @"Available input types %@", inputTypes);         
      
      //Check that all the plugins requirements are present.
      //When we find that a required  plugin input is present 
      //we remove it from the inputTypes array.
      //At the end if there are any entries left in inputTypes
      //it means the plugin cant process them and we have to return NO.
      
      inputsEnum = [pluginInputs objectEnumerator];
      while(input = [inputsEnum nextObject])
      {
            //check if the input type exists
            inputType = [input objectForKey: @"ULInputObject"];
            number = [objectsCountDict objectForKey: inputType];
            NSDebugLLog(@"ULAnalysisManager", @"Checking for input objects of type %@", inputType);
            minimumNumber = [input objectForKey: @"ULInputObjectMinimumNumber"];
            maximumNumber = [input objectForKey: @"ULInputObjectMaximumNumber"];

            if(minimumNumber == nil)
            {
                  NSWarnLog(@"ULInputObjectMinimumNumber key missing from plugin input information");
                  return NO;
            }

            if(maximumNumber == nil)
            {
                  NSWarnLog(@"ULInputObjectMaximumNumber key missing from plugin input information");
                  return NO;
            }

            
            NSDebugLLog(@"ULAnalysisManager", @"Mininum required number %@ maximum number %@", 
                  minimumNumber, 
                  maximumNumber);
            
            //if there are no inputs of this type check if its optional
            //if its required return NO
            if(number == nil)
            {
                  NSDebugLLog(@"ULAnalysisManager", 
                        @"No inputs of this type! Checking if optional");
                  if([minimumNumber intValue] != 0)
                  {
                        NSDebugLLog(@"ULAnalysisManager", 
                              @"Required type - plugin cant process current inputs");
                        return NO;
                  }
                        
                  NSDebugLLog(@"ULAnalysisManager", 
                        @"Input optional - continuing");    
            }           
            else
            {
                  //check if its greater than or equal to the minimum number

                  if(!([number intValue] <= [maximumNumber intValue] && 
                        [number intValue] >= [minimumNumber intValue]))
                  {
                        NSDebugLLog(@"ULAnalysisManager", 
                              @"The number of inputs of type %@ (%@) is incorrect", 
                              inputType, 
                              number);
                        return NO;
                  }
                  else
                              //remove this object from the inputTypes array
                        [inputTypes removeObject: inputType];
            }
      }     

      if([inputTypes count] != 0)
            return NO;
            
      return YES;
}

00453 - (NSArray*) pluginsForCurrentInputs
{
      NSEnumerator *pluginEnum;
      NSMutableArray *array = [NSMutableArray array];
      NSString *plugin;

      if([inputObjects count] != 0)
      {
            pluginEnum = [availablePlugins objectEnumerator];
            while(plugin = [pluginEnum nextObject])
                  if([self _pluginCanProcessCurrentInputs: plugin])
                        [array addObject: plugin];
      }                 

      return array;
}

00470 - (id) outputDataSets 
{ 
      return [results objectForKey: @"ULAnalysisPluginDataSets"];
}

00475 - (id) outputString 
{ 
      return [results objectForKey: @"ULAnalysisPluginString"];
}

@end

Generated by  Doxygen 1.6.0   Back to index