<?xml version='1.0' encoding="iso-8859-1"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
        "/usr/share/sgml/docbook/dtd/xml/4.2/docbookx.dtd" >

<article lang="en">
  <title>Making a new module for ArgoUML</title>

  <articleinfo>
    <authorgroup>
      <author>
	<firstname>Florent</firstname><surname>de LAMOTTE</surname>
      </author>
    </authorgroup>
  </articleinfo>
  <abstract>
    <para>
      This document has been extracted from some tutorial in french and converted to english, it
      should help people who want to write modules for ArgoUML. (note that the depth of the titles
      have been preserved, it will make me easier to traduce the whole document)
    </para>
    <para>
      You will find the example that I wrote while I was writing this document
      <ulink url="testDiagram.tar.gz">here</ulink>. You can test it directly untaring it in
      the right directory (modules) and running the command <command>ant run</command> in the
      newly created directory (you should have developpement tools correctly installed if you
      want to do that.
    </para>
  </abstract>
  <sect1>
    <title>Creating a module</title>
    <sect2>
      <title>Creating a module</title>
      <sect3>
	<title>Configuring the module</title>
	<para>
	  First, you will have to create a directory in <filename>argouml/modules</filename> where you will put
	  all the files that will be used by your module. In our example, we will call this directory 
	  <filename>test</filename>.
	</para>
	<para>
	  In this directory, you will first place a <filename>build.xml</filename> file, this is a configuration
	  file for ant, you will create a <filename>module.properties</filename> file too, in this file, you will
	  place some parameters related to your module. You will find these files in other module's source such
	  as the php module.
	</para>
	<para>
	  If you use <filename>build.xml</filename> from php module, you should have nothing to modify because for
	  this modules, all the parameters related to the module are placed in <filename>module.properties</filename>
	  (however as the Junit module uses external libraries, the <filename>build.xml</filename> file is slightly
	  different).
	</para>
	<para>
	  The file <filename>module.properties</filename> is composed of two lines for the moment, these lines are
	  ant properties.
	  <itemizedlist>
	    <listitem>
	      <para>
		<emphasis>argo.module.name</emphasis> let you specify the name of the module
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		<emphasis>argo.module.jarfile</emphasis> let you specify the name you want for the jar archive
	      </para>
	    </listitem>
	  </itemizedlist>
	</para>
	<para>
	  For our module, the property file will contain this :
	  <programlisting>
argo.module.name=test
argo.module.jarfile=argo_test
	  </programlisting>
	</para>
	<para>
	  Once your <filename>build.xml</filename> and <filename>module.properties</filename> files are ready, you can
	  test your module's configuration by typing <command>ant</command>.
	</para>
	<para>
	  Here is what ant should tell you :
	</para>
	<programlisting>
	  <![CDATA[
$ ant
Buildfile: build.xml

init:
     [echo] ------------------- ArgoModule-test 0.9.5-20020718-0858 [2001] ----------------

usage:
     [echo] 
     [echo] 
     [echo] ArgoModule-test Build file
     [echo] -------------------------------------------------------------
     [echo] 
     [echo]  available targets are:
     [echo] 
     [echo]    compile      --> compiles the source code to the tree under ../../modules/test/build
     [echo]    package      --> generates the argo_test.jar file
     [echo]    run          --> runs ArgoUML argo_test.jar
     [echo]    install      --> merges ./org into ../src_new/org tree
     [echo]    usage        --> show this message (default)
     [echo] 
     [echo]  See the comments inside the build.xml file for more details.
     [echo] -------------------------------------------------------------
     [echo] 
     [echo] 

BUILD SUCCESSFUL
Total time: 2 seconds
	  ]]>
	</programlisting>
	<para>
	  You should have obtained something similar, verify that the archive name is the one you
	  have asked, you should see this on the lines <emphasis>package</emphasis> and
	  <emphasis>run</emphasis>. You can also verify the name of the module, you should see
	  <emphasis>ArgoModule-test</emphasis> during init.
	</para>
      </sect3>
      <sect3>
	<title>Setting up the directory hierarchy</title>
	<para>
	  When ant is configured, you can create the directory hierarchy.
	</para>
	<para>
	  First, create the directory <filename>src</filename> that will hold the sources
	  (the package hierarchy). In this director, you will have to put the root of the package
	  hierarchy (<filename>org/argouml</filename>).
	</para>
	<para>
	  You should also create a <filename>lib</filename> directory where you will put external 
	  libraries.
	</para>
      </sect3>
      <sect3>
	<title>The manifest.mf for argo modules</title>
	<para>
	  If you want module loading not to fail, you should write a <filename>manifest.mf</filename> 
	  file where you will put necessary information for the module to load. Here is the 
	  <filename>manifest.mf</filename> file for our module <emphasis>test</emphasis>.
	</para>
	<programlisting>
	  <![CDATA[
Manifest-Version: 2.0
Class-Path: test.jar
Created-By: 1.3.1 (Sun Microsystem Inc.)

Name: org/argouml/uml/ui/ActionTestDiagram.class
Extension-name: module.tools.test
Specification-Title: ArgoUML Dynamic Load Module
Specification-Version: 0.9.10
Specification-Vendor: University of California
Implementation-Title: Test Module
Implementation-Version: 0.9.10
Implementation-Vendor: test
	  ]]>
	</programlisting>
	<para>
	  I feel like I should explain it a little bit ...
	</para>
	<para>
	  <itemizedlist>
	    <listitem>
	      <para>
		The <emphasis>Manifest-Version</emphasis> field let you specify the version
		of the format used, here it is 2.0.
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		The <emphasis>ClassPath</emphasis> field gives us the name of the jar files that
		will be loaded with our module
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		The <emphasis>Created-By</emphasis> field contains the name of the compiler used 
		for the classes.
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		The <emphasis>Name</emphasis> field let you give the name of the main class, 
		this class will be loaded by Argo's classloader as a module.
	      </para>
	    </listitem>
	    <listitem>
	      <para>
		...
	      </para>
	    </listitem>
	  </itemizedlist>
	</para>
	<para>
	  <filename>manifest.mf</filename> should be put at the root of the archive, in
	  the <filename>src/org</filename> directory.
	</para>
      </sect3>
      <sect3>
	<title>A little test</title>
	<para>
	  We will now be able to test that everything is ok before starting.
	</para>	
	<para>
	  First, we will try to package our program with the command :
	  <command>ant package</command> that you should execute in the base directory 
	  for your module.
	</para>
	<programlisting>
	  <![CDATA[
$ ant package
Buildfile: build.xml

init:
     [echo] ------------------- ArgoModule-test 0.9.5-20020718-0941 [2001] ----------------

prepare:
     [echo] Preparing the build directories

compile:
     [echo] Compiling the sources

package:
     [copy] Copying 1 file to /usr/src/argo/modules/test/build/classes
      [jar] Building jar: /usr/src/argo/modules/test/build/argo_test.jar

BUILD SUCCESSFUL

Total time: 3 seconds
	  ]]>
	</programlisting>
	<para>
	  Once again, you should have obtained the same result. When the execution of the command
	  is over, a <filename>build/argo_test.jar</filename> file should have been created.
	</para>
	<para>
	  The newly generated archive file <filename>argo_test.jar</filename> should only contain
	  <filename>manifestt.mf</filename> file.
	</para>
	<para>
	  You can also try <command>ant run</command> that should normally launch ArgoUML with your
	  module. As the class you have specified in the <emphasis>Name</emphasis> field of the
	  <filename>manifest.mf</filename> doesn't exist the loading of the module should fail and
	  you should see :
	  <programlisting>
     [java] Could not instantiate module org/argouml/uml/ui/ActionTestDiagram
	  </programlisting>
	</para>
	<para>
	  If ArgoUML doesn't even launch and that you obtain
	</para>
	<programlisting>
	  <![CDATA[
run:
     [echo] --- Executing ArgoModule-test ---
     [java] Exception in thread "main" java.lang.NoClassDefFoundError: org/argouml/application/Main
     [java] Java Result: 1
	  ]]>
	</programlisting>
	<para>
	  That's because you haven't created <filename>argouml.jar</filename> that need to be placed
	  in Argo's <filename>build</filename> directory.
	</para>
	<para>
	  A simple <command>ant package</command> in <filename>src_new</filename> directory should 
	  solve the problem.
	</para>
      </sect3>
    </sect2>
    <sect2>
      <title>Adding a command to the menus</title>
      <para>
	In order to create a new diagram, we must create a new entry in one of Argo's menus. To achieve that,
	we will use functionnalites from the <classname>PluggableMenu</classname> interface.
      </para>
      <sect3>
	<title>PluggableMenu</title>
	<para>
	  <classname>PluggableMenu</classname> is an interface that let you create PlugIns for Argo that adds
	  an entry into the menus. <classname>PluggableMenu</classname> comes from <classname>Pluggable</classname>
	  which in its turn comes from <classname>Module</classname>.
	</para>
	<para>
	  Next figure presents the class diagram corresponding to modules.
	</para>
	<figure id="fig_modules">
	  <title>Modules class diagram</title>
	  <mediaobject>
	    <imageobject>
	      <imagedata fileref="images/modules.gif" format="GIF"/>
	    </imageobject>
	    <textobject>
	      <phrase>L'image n'a pas pu être affichée</phrase>
	    </textobject>
	  </mediaobject>
	</figure>
	<para>
	  Methods providedd by the <classname>Module</classname> interface are mainly used to identify the module,
	  to initialize it and finally to close it in a clean way.
	</para>
	<para>
	  The <function>inContext</function> methode from the <classname>Pluggable</classname> interface
	  is used by the pluggin to plug itself to some part of Argo.
	</para>
	<para>
	  <function>getMenuItem</function> method from the <classname>PluggableMenu</classname> interface is
	  the function by which Argo will be able to get the <classname>JMenuItem</classname> provided by
	  our <classname>PluggableMenu</classname> and insert it in the good <emphasis>context</emphasis>
	  which was asked by argo before.
	</para>
	<para>
	  The <function>buildContext</function> method from the <classname>PluggableMenu</classname> interface
	  is used to make the array of <classname>Objects</classname> that will be passed as arguments to
	  the <function>inContext</function> method. This method is used by Argo to build the context for modules
	  but I haven't been able to see why. (maybe it can be usefull when you so some inheritance ?)
	</para>
	<para>
	  The sequence diagram coming next explains how the insertion of an entry in the menu of ArgoUML is done.
	</para>
	<figure>
	  <title>Inserting a menu</title>
	  <mediaobject>
	    <imageobject>
	      <imagedata fileref="images/chargement_pluggable_menu.gif" format="GIF"/>
	    </imageobject>
	    <textobject>
	      <phrase>Désolé, l'image n'a pas pu être affichée</phrase>
	    </textobject>
	  </mediaobject>
	</figure>
      </sect3>
      <sect3>
	<title>Our PluggableMenu</title>
	<para>
	  We will now write our own <classname>PluggableMenu</classname>. We will name it 
	  <classname>ActionTestDiagram</classname>, it will be a son for the class <classname>UMLAction</classname>
	  while implementing <classname>PluggableMenu</classname> (this will permit us to have in the same class
	  the action that creates the MenuItem and the one that is executed when it is selected).
	</para>
	<para>
	  Our new class will implement all the methods from <classname>Module</classname>, <classname>Pluggable</classname>
	  and <classname>PluggableMenu</classname>, and will also implement <function>ActionPerformed</function> 
	  that will be the action executed when our menuItem will be seclected (for the begining it will be
	  a simple <function>System.out.println</function>.
	</para>
	<para>
	  This new class will be placed in the directory <filename>src/org/argouml/uml/ui</filename> that you must 
	  create and will be part of the <classname>org.argouml.uml.ui</classname> package.
	</para>
	<programlisting format="linespecific">
	  <![CDATA[
package org.argouml.uml.ui;

import org.argouml.ui.*;
import org.argouml.application.api.*;
import org.argouml.uml.ui.*;
import org.argouml.uml.*;
import org.argouml.kernel.*;

import org.tigris.gef.base.*;
import org.tigris.gef.util.*;

import ru.novosoft.uml.foundation.core.*;
import ru.novosoft.uml.behavior.state_machines.*;
import ru.novosoft.uml.model_management.*;

import java.awt.event.*;
import java.io.*;
import java.util.*;

import javax.swing.*;
import java.beans.*;

/**
 * Notre classe ActionTestDiagram
 */
public class ActionTestDiagram extends UMLAction
     implements PluggableMenu {

     public ActionTestDiagram() { super ("TestDiagram"); }

     private static JMenuItem _menuItem = null;

     /////////////////////////////////////////
     // implementation de UMLAction

     /**
      * Action executée par la selection du menu
      */
     public void actionPerformed (ActionEvent ae) {
	  System.out.println("HelloWorld!!");
     }


     /////////////////////////////////////////////////////////////////
     // implementation de l'interface Module

     private boolean _initialized = false;

     public boolean initializeModule() {
	  Argo.log.info("*** Initialisation de TestDiagram");

	  _initialized = true;

	  return _initialized;
     }


     public void setModuleEnabled(boolean enabled) { }
     public boolean isModuleEnabled() { return true; }
     public Vector getModulePopUpActions(Vector v, Object o) { return null; }
     public boolean shutdownModule() { return true; }

     public String getModuleName() { return "TestDiagram"; }
     public String getModuleDescription() { return "TestDiagram"; }
     public String getModuleAuthor() { return "Florent de Lamotte"; }
     public String getModuleVersion() { return "0.9.10"; }
     public String getModuleKey() { return "module.tools.test"; }


     /////////////////////////////////////////////////////////////////
     // Implémentation de l'interface Pluggable

     /**
      * Permet au module d'insérer le menu ou il le veut
      * @param o l'objet décrivant le contexte le premier objet est un JMenuItem 
      * et le second une clé correspondant à ce JMenuItem et correspondant à une entrée
      * dans le menu
      * @return true si l'emplacement nous convient
      */
     public boolean inContext(Object[] o) {
	  if (o.length < 2) return false;
	  if ((o[0] instanceof JMenuItem) && ("Create Diagrams".equals(o[1]))) {
	       return true;
	  }
	  return false;
     }

     /////////////////////////////////////////////////////////////////
     // Implémentation de l'interface PluggableMenu

     /**
      * Retourne le JMenuItem que l'on veut ajouter au menu
      *
      * @param mi le JMenuItem dans lequel sera ajouté notre JMenuItem
      * @param s  La clé correspondante (celle qui avait été passée lors du inContext
      * @return Le JMenuItem correspondant à ce menu
      */
     public JMenuItem getMenuItem(JMenuItem mi, String s) {
	  if (_menuItem == null) {
	       _menuItem = new JMenuItem("Test Diagram",
					 ResourceLoader.lookupIconResource("TestDiagram"));
	  }
	  _menuItem.addActionListener(this);
	       
	  return _menuItem;
     }

     /**
      * Construit l'objet qui sera envoyé a inContext
      */
     public Object[] buildContext(JMenuItem a, String b) {
	  return new Object[] { a, b };
     }
}
	  ]]>
	</programlisting>
	<para>
	  Once the new class is written, you can launch ArgoUML with your new module by executing
	  the command <command>ant run</command> from your module's directory.
	</para>
	<para>
	  Your module should be loaded by Argo and you should see the following message
	  <programlisting>
	    <![CDATA[
     [java] *** Initialisation de TestDiagram
     [java] Loaded Module: TestDiagram
	    ]]>
	  </programlisting>
	  In the "Create Diagram" entry in the menu, a new item should appear : "Test Diagram",
	  if you select this item, <emphasis>HelloWorld!!</emphasis> should appear on the console.
	</para>
	<para>
	  While the module is loading, it complains because it can't find an Icon ...
	  In fact, when we created our <classname>JMenuItem</classname>, we associated it 
	  the icon <emphasis>TestDiagram</emphasis> that we have neither created nor placed
	  in the jar.
	</para>
	<para>
	  Icons are placed in the directory <filename>src/org/argouml/Imafes</filename> so you
	  can put an icon with the name <filename>TestDiagram.gif</filename> in the 
	  <emphasis>gif</emphasis> format in this directory.
	</para>
	<para>
	  We will now have to make a little modification in our <filename>build.xml</filename> file
	  so that it can copy every icon from the <filename>src/org/argouml/Images</filename> directory
	  int hte <filename>build/classes/org/argouml/Images</filename> directory, that will then enable
	  GEF to find the icon (in fact it is the <classname>RessourceLoader</classname> from GEF 
	  that does this task.)
	</para>
	<para>
	  The modifications are added to the <emphasis>prepare</emphasis> target which aim is to 
	  prepare the directories where the files to be archived are placed.
	</para>
	<programlisting>
	  <![CDATA[
  <!-- =================================================================== -->
  <!-- Prepares the build directory                                        -->
  <!-- =================================================================== -->
  <target name="prepare" depends="init">
    <!-- create directories -->
    <echo message="Preparing the build directories"/>
    <copy todir="${module.build.dest}/org/argouml/Images">
       <fileset dir="${module.build.src}/org/argouml/Images"
              includes="**/**" excludes="CVS/**"/>
    </copy>               
  <!-- These must be there already -->
  </target>
	  ]]>
	</programlisting>
	<para>
	  Now if you execute <command>ant run</command>, you should see your icon near the text of
	  your <classname>JMenuItem</classname>.
	</para>
      </sect3>
    </sect2>
  </sect1>
</article>

<!-- Keep this comment at the end of the file
Local variables:
mode: xml
sgml-omittag:nil
sgml-shorttag:nil
sgml-namecase-general:nil
sgml-general-insert-case:lower
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:2
sgml-indent-data:t
sgml-parent-document:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->
