Working with Custom Properties, Save and Load in .Net plug-ins
This tutorial begins with a technical explanation of how Chameleon uses a plug-in and then moves into the related areas of custom properties and load/save functionality. In short, there are two ways to populate a custom property, either through the custom properties tab on the Chameleon GUI or through the Load/Save methods.
At startup, Chameleon goes through the classes in the plug-in folder and instantiates and holds a pointer to all classes that implement the IChameleonPlugin Interface. The user has two options after Chameleon has started up: you can either select plug-ins, load data files, set custom properties, and run or you can load a previously saved automation session (a .cham file) and run. In either case, once you click run, each selected plug-in's Initialize(), Execute(), and Clean() methods will be called in that order. So, in reality, the minimum set of methods that must be implemented to create a working plug-in are those three. The Chameleon command line client only loads .cham files so it is necessary to implement the Load/Save methods if you plan to use your plug-in on the command line.
Save and Load
Chameleon Automation Session files are XML files that can be used to save state from one Chameleon session to the next. The Save and Load methods are the way plug-ins save and retrieve state information. These will only be used when a plug-in has custom properties, or in other words, when a plug-in needs more information than just the list of files to run and the feedback delegate. The Load method will be run for every plug-in, every time a .cham file is loaded and Save will be run for every plug-in, every time a .cham file is saved. As you can see in the documentation Save returns a string, and Load takes a single string argument.
Example: .cham file snippet for FileSplitter
<algorithm checked="True" name="Universal.Converter.FileSplitter">
<Custom_Data>12000</Custom_Data>
</algorithm>
Example: Save() Method for FileSplitter
/// <summary>
/// Saves this plug-in's custom property
/// </summary>
/// <returns>A string equivalent of myMaxLines.
/// The Chameleon client will handle all the XML processing
/// </returns>
/// <remarks>If multiple custom properties were present
/// a delimiter (programmer's choice) would need to be added
/// </remarks>
public string Save()
{
return myMaxLines.ToString();
}
Example: Load() Method for FileSplitter
/// <summary> /// This essentially does the exact opposite of Save. /// Since we know how the string is supposed to be formatted, we unpack /// and populate the proper custom properties. /// This is only called when the user loads a .cham file. /// </summary> /// <param name="loadValue">The value saved by the client in the .cham file /// for this plug-in</param> /// <returns>True if loaded successfully, false if there was a problem</returns> public bool Load(string loadValue) { if (loadValue.Length < 1) return true; //we need to be a little paranoid here because //this input could be coming from anywhere and //be in any state. Thus the try..catch block. try { myMaxLines = Convert.ToInt32(loadValue); return true; } catch { //if something went horribly wrong, like a bad format, //return false to tell the client to alert the user. return false; } }
Custom Properties
Now on to custom properties and the reason Load/Save is necessary. First off, Properties are essentially like getter and setter methods in Java and C++ only combined into a single easy to use method; they are used for abstraction. Sometimes plug-ins require information from the user in order to perform some action. FileSplitter, for example, requires more information because it needs to know the desired file-chunk size. So, all a custom property is, is a property in your IChameleonPlugin that maps to a private data member that the plug-in uses in its calculations.
Example: Part of the FileSplitter Class to show the custom property for MaxLines
namespace Universal.Converter
{
using System;
using System.IO;
using System.ComponentModel;
using BKTech.Chameleon.Plugins;
/// <summary>
/// This plug-in splits its input files into smaller files.
/// </summary>
/// <remarks>This is useful for dealing with size limits of
/// other programs</remarks>
public class FileSplitter : IChameleonPlugin
{
//the maximum number of lines to write in each of the split files
private int myMaxLines = 50000;
[Browsable(true),
Description("The maximum number of lines you wish to have in " +
"each split file.")]
public int MaxLines
{
get { return this.myMaxLines; }
set { this.myMaxLines = value; }
}
// ...
} //end class
} //end namespace
Some key points. The Browsable(true) attribute above the MaxLines declaration allows Chameleon to see the property. The Description(...) attribute puts a text description at the bottom of the custom properties tab so users know what the property is supposed to be used for. Browsable is required for Chameleon to be able to see the property, Description is not required but is a good thing to have. You can enter values directly into the properties (and thus private data members) via the Chameleon GUI custom properties tab. Be sure to click on the plug-in whose properties you want to change.
So, in summary, there are two ways a custom property can be populated. If you load a .cham file that has load information for that plug-in in it (and you've properly implemented the load method for that data) or if you enter the information directly into a plug-in's custom property via the custom properties tab on the Chameleon GUI.
A bit about Clean()
If Clean() returns false (which is the .Net default if you don't return anything) Chameleon assumes that the plug-in went out of control and is unable to reset itself for future use. Chameleon will wipe the plug-in from memory and reinstantiate it leaving all custom properties set back to default. Clean is called after a plug-in is executed. All the cleaner does is prepare the plug-in for future use by clearing the data files array, releasing the delegate (setting the reporter to null), and releasing any other classes you may be used that aren't custom properties.