Computational-Intelligence

News-Archiv

[ Welcome | Application | Repository | Documentation ]

This is the preliminary documentation of the build principles of Infominer. They will be accumulated here until a proper substructuring suggests itself.

Repository Layout

The top-level directory (/trunk) contains four subfolders with the following contents.

  • /data
    Contains some test data for analysis as well as example models.
  • /dev
    Root directory for the development.
  • /redist
    Target directory for the ready-to-use distribution.
  • /work
    Other stuff like flyers, logo files, and other assets.

Development Directory Structure (/dev)

This directory contains four subfolders as indicated on the left image as well as the main two build files: build.xml and common-targets.xml. Folders data and core are proper project directories (the layout of which is described later on) whereas tasks serves as a toplevel directory for the several module projects. libs is not a project but contains all those libraries that are required by at least two projects. (libraries needed for only a single project are contained in the project's own library directory.)

Project Structure

The image depicts a typical project directory (as for data, core and the tasks). The folders in italics are not inside the repository but are created upon build via build.xml. Each project has to provide its own build file but may be dependent on other projects. Currently data is stand-alone, core depends on data and every task depends on both core and data. Inter-task dependencies are not yet necessary.

How to write a custom task?

In the following we will demonstrate the creation of a new task from scratch. Since a HelloWorldTask wouldn't quite fit our needs, we use the MultiNetViewerTask as an example. It is used to display an aggregated view of a multitude of graphs.

First of all, create a new class called MultiNetViewerTask (by convention, all task class names end on Task) and let it derive from edu.unimd.cs.fuzzy.infominer.core.task.AbstractTask. Tell your IDE to generate method stubs for all abstract methods as there are: registerSlots and run. In addition to that augment the class definition with the two constructors from the base class. The naked class frame should now look as follows:

public class MultiNetViewerTask extends AbstractTask
{

	public MultiNetViewerTask(TaskManager mgrOwner)
	{
		super(mgrOwner);
	}

	public MultiNetViewerTask(TaskManager mgrOwner, Element elmTask, Logger log)
	{
		super(mgrOwner, elmTask, log);
	}

	@Override
	protected void registerSlots()
	{
	}

	public void run()
	{
	}
}

Let's set up the task further. Add a static logger instance variable as well as an internationalization helper that automatically finds the appropriate terms for the slot names.

    private static final Logger s_log = Logger.getLogger(Module.LOG_TASKS_INES);
    private static final I18n s_i18n = new I18n(ResRoot.class);

We assume here, that Module is a valid module descriptor class of the current module and that LOG_TASKS_INES contains the logger name. Further the class ResRoot resides in a resource package, which has to contains the files i18n_XY.properties were XY represents the respective locale suffix like de or en.

Now it's time for our first (and in this case only) slot, the connection slot that serves as out only input.

    private ConnectionSlot m_slotInNets = null;

To make this slot available it has to be registered (and created, of course) which is done via -- you will guess it -- registerSlots. Add the following code.

        m_image = Utils.createImage(ResRoot.class, "task-netview-large.gif");

        registerInputSlot(
        	m_slotInNets = new ConnectionSlot(
        		this, "InNets", s_i18n,
        		Vector.class ));

As you can see, we abuse the method by setting an appropriate icon for the task as well. m_image is a member of AbstractTask. The creation of the input slot needs a reference to the owning task (this), a string name ("InNets") to address the slot, the internationalization helper (s_i18n) and the type of the object that the slot shall contain (in our case a Vector).

Now that we have finished the slot registration, we have to make sure, it is invoked. So, add the respective call to both constructors. In the same instant, call initSlotsFromXml from the constructor that has the Element argument. The first constructor is called when the user drags a task into the graph area. The second one is invoked when a model is loaded from file. The class should now look as follows:

public class MultiNetViewerTask extends AbstractTask
{
    private static final Logger s_log = Logger.getLogger(Module.LOG_TASKS_INES);
    private static final I18n s_i18n = new I18n(ResRoot.class);

    private ConnectionSlot m_slotInNets = null;

	public MultiNetViewerTask(TaskManager mgrOwner)
	{
		super(mgrOwner);

		registerSlots();
	}

	public MultiNetViewerTask(TaskManager mgrOwner, Element elmTask)
	{
		super(mgrOwner, elmTask, s_log);

		registerSlots();
		initSlotsFromXml(elmTask, s_log);
	}

	@Override
	protected void registerSlots()
	{
		m_image = Utils.createImage(ResRoot.class, "task-netview-large.gif");

		registerInputSlot(
        	m_slotInNets = new ConnectionSlot(
        		this, "InNets", s_i18n,
        		Vector.class ));
	}

	public void run()
	{
	}
}

This is already sufficient for the task to be plugged into Infominer. If you want to give it a try, make sure that the module descriptor class has something similar to the following line in it's constructor:

	defineTask("MultiNet Viewer", "Data Mining/Graphical Models", MultiNetViewerTask.class);

You should then be able to create a MultiNetViewerTask object.

Let us now turn to the interesting part: the lifecycle of the task which is implemented by the run method. Whenever a task is started, the run method is invoked and should set the task's state to running:

        try { helperBeginRun(s_log); } catch (Exception e) { return; }

The helperBeginRun method does exactly this by resetting the task (i.e. deleting the values of all output slots, if any), setting the state to RUNNING and start a so-called progressor thread that maintains this nice gradient rotation animation.

As helperBeginRun marks the entry of the run method, make sure that every possible exit of the method calls helperFinishRun or helperError as their last statement. The first sets the state to OUTPUTS_READY, the second to ERROR and creating an appropriate error event.

Now let's access the input connection slot. We claim the input value via getValueForced which may cause the task whose output slot connects to our input slot to run if the output is not present yet. We end the tutorial by just displaying the size of the input vector since the remaining code wouldn't add to the principal understanding. The final run method looks as follows:

	public void run()
	{
        try { helperBeginRun(s_log); } catch (Exception e) { return; }


        Vector<NetworkInfo> vecNets = (Vector<NetworkInfo>)m_slotInNets.getValueForced(s_log);
        if (vecNets == null)
        {
        	helperError("input slot is null", s_log);
        	return;
        }

        s_log.info("there are " + vecNets.size() + " nets in the vector.");

        helperFinishRun(s_log);
	}
en lang icon de lang icon Printable View - Recent Changes
Page last modified on August 01, 2007, at 10:41 AM by msteinbr