Translations of this page:

Plugin Development

Develop an Osmius Plugin is very easy. We have choose Grooy to the development of Osmius Plugins.

Osmius Development Team has develop a miniSDK that serves as guide when you planned to develop a new Plugin. You can download the SDK via the following address:

As you can see, there are very few classes and methods. We have tried to prime the simplicity when developing a new plugin. Eventually, a plugin is a zip file consists of:

  • A file describing the plugin, plugin.xml
  • A .jar file. that contains classes that perform the actions when you install the plugin.
  • Additional files used to install the plugin.

The first thing we are going to discuss is the plugin.xml file. Has the following form:

 <plugin>
   <idnPlugin>org.osmius.plugins.Plugin/idnPlugin>
   <clsName>org.osmius.plugins.TestPlugin</clsName>
   <desPlugin>Plugin de ejmplo</desPlugin>
   <idnVersion>1.0</idnVersion>
   <jarPlugin>plugin.jar</jarPlugin>
   <dtiCreated>2010-04-12 15:50:32.350 CEST</dtiCreated>
   <txtAuthor>Develover</txtAuthor>
   <txtMail>developer@peopleware.es</txtMail>
   <txtUrl>www.osmius.com</txtUrl>
   <txtKey></txtKey>
   <idnFree>1</idnFree>
   <txtFiles>plugin.jar</txtFiles>
 </plugin>
  • idnPluguin: plugin identificator. Must be unique in the system.
  • clsName: indicates the name of the class that the console must load for execution. The plugins should be packaged within org.osmius.plugins
  • desPlugin: a description of the plugin (1024 characters maximum)
  • idnVersion: plugin version
  • jarPlugin: jar file containing the plugin classes
  • dtiCreated: plugin creation date
  • txtAuthor: Developer
  • txtMail: Developer e-mail
  • txtUrl: Developer Web
  • txtKey: Developer key (unused at this moment)
  • idnFree: free or paid Plugin
  • txtFile: Files that go into the zip except plugin.xml

This file is used by the console to the management of loaded plugins and by plugin itself for upgrades, etc.

Turning now to code level, we begin with two very basic classes: Message and OsmiusResponse.

  • Message is a class that consists of 3 properties: messages, langcode and description.

As we could see a little later, the plugin installation process is based on the exchange of messages. A properly installed plugin should always return the PLG-00000 code. With that code the console can know it the plugin installation proccess has finished. langcode field indicates the language that should be returned to the description of the message within the description field.

* OsmiusResponse class has only two fields and one error message. error is a boolean that helps us to determine whether a transaction is wrong or not. The message code PLG-00000 corresponds to an error = false in OsmiusResponse object.

Through these two classes is easy to establish a protocol for exchanging messages between the console and the plugin.

When developing a plugin, is required to fulfill an interface, which we called OsmiusPlugin. This interface defines the following 2 methods:

  • public OsmiusResponse execute(Connection conn, ClassLoader classLoader, Locale locale, String version, String workingDir,String messageID);
  • public int getMesageID(String messageID);

getMessage method converts messages codes to numeric values, an example message PLG-00000 in a numeric value, 0, which is much easier to be treated for example in a switch statement.

The execute method is really important. The developer must implement the logic of the plugin in this method. As you can see, this method returns an object OsmiusResponse, which tells the console the result of actions implemented by the plugin.

The execute method receives 6 parameters:

  • Connection conn: is a connection to the Osmius database to execute SQL statements (under the responsibility of plugin developers).
  • ClassLoader classloader: this is a typical Java class loader that allows the plugin to load resource files in an easy manner.
  • Locale locale: parameter to determine which language should return messages ok / error.
  • String version: the version of the console, to determine if the plugin may or may not be executed on certain console version.
  • String WorkingDir: plugin working directory where you can perform the operations you want, unzip files, etc.
  • String message: this object is initially null. Depending on the implementation of the plugin, for example may be an update, the plugin returns an OsmiusResponse object with false as error and PLG-XXXXX as messageID, then the console will display the text of the message, which will be of type 'Do you want to update …?'. If we accepted, the console plugin will sent back to the plugin the PLG-XXXXX messageID and the plugin could continue the installation of the plugin from that particular point.

To facilitate the development, the Osmius team provides a base class, OsmiusPluginBase. All new plugins must extend it. Methods of this class are:

  • public abstract boolean checkConsoleVersion (String version): A method to test the console version
  • public abstract State getStatePluginVersion (Connection conn, String pluginName, String pluginVersion): A method for testing the state of the plugin, not installed, same version, previous version, new version
  • public String getDBPluginVersion (Connection conn, String pluginName): A method for database currently installed version

We also provide an enum, State, to determine the possible states of a plugin: NOT_INSTALLED, SAME_VERSION, MINOR_VERSION, MAYOR_VERSION A possible example of implementation of a plugin could be:

class Plugin extends OsmiusPluginBase {
   OsmiusResponse execute(Connection conn, ClassLoader classLoader, Locale locale, String version, String workingDir, String messageID) {
      def messages = ResourceBundle.getBundle("org_osmius_plugins_Plugin", locale, classLoader)
      def pluginXML =  new XmlSlurper().parseText(new File(classLoader.getResource("plugin.xml").toString().toURI()).text)
      String pluginVersion = pluginXML.idnVersion
      OsmiusResponse response = new OsmiusResponse(false, new Message("PLG-00000", locale.getLanguage(), messages.getString("PLG-00000")));
      try {
	 if (checkConsoleVersion(version)) { // First: Check version
	    int msgID = getMesageID(messageID);
	    switch (msgID) {
	       case -1: // First Time : messageID null -> -1
	          def state = getStatePluginVersion(conn, "org.osmius.plugins.Plugin", pluginVersion)
	          switch (state) {
	             case State.NOT_INSTALLED:
	                def sql = new Sql(conn)
	                sql.execute("INSERT INTO PRUEBA (FECHA) VALUE (NOW()) ")
	                break
	             case State.SAME_VERSION: // ERROR: Plugin is already installed
	                response.setError(true);
	                response.setMessage(new Message("PLG-01001", locale.getLanguage(), messages.getString("PLG-01001")))
	                break
	             case State.MINOR_VERSION: // ERROR: Trying to install a previous version
	                response.setError(true);
	                response.setMessage(new Message("PLG-01002", locale.getLanguage(), messages.getString("PLG-01002")))
	                break
	             case State.MAYOR_VERSION: // NO ERROR - INFO Message to install new version
	                response.setError(false);
	                response.setMessage(new Message("PLG-01003", locale.getLanguage(), messages.getString("PLG-01003")))
	                break
	          }
	          break
	       case 1003:
	          // Hacer la acción/es que deseemos
	          break
	       default:
	          break
	    }
	 } else { // ERROR : Plugin can not be installed on this Console version
	    response.setError(true);
	    response.setMessage(new Message("PLG-01000", locale.getLanguage(), messages.getString("PLG-01000") + version))
	 }
      } catch (Exception e) {
	 response.setError(true)
	 response.setMessage(new Message("PLG-00001", locale.getLanguage(), messages.getString("PLG-00001") + e.printStackTrace()))
      }
      return response;
   }
   boolean checkConsoleVersion(String version) {
      boolean value = true
      if (version < "v10.04") { //Only works with v10.04
	 value = false
      }
      return value
   }
   State getStatePluginVersion(Connection conn, String pluginName, String pluginVersion) {
      State value = State.NOT_INSTALLED
      def version = getDBPluginVersion(conn, pluginName)
      if (version == "") { // No plugin installed
	 value = State.NOT_INSTALLED
      } else if (version == pluginVersion) {
	 value = State.SAME_VERSION
      } else if (pluginVersion < version) {
	 value = State.MINOR_VERSION
      } else if (pluginVersion > version) {
	 value = State.MAYOR_VERSION
      }
      return value
   }
}

To do things even easier, we have developed a class to install easiy new agentes developed by users. The unique things the developer must to are: firstly develop the Osmius agent, and next use this class (you haven't to rewrite it) modify the properties of a new xml file osmiusPluginAgent.xml.

The osmiusPluginAgent.xml file has the following structure:

  • typeAgent : new Agent Type to be included on Osmius.
  • typePlataforms : Platform (windows, linux,…) in which the agent can be executed.
  • sqlNewFile : file with necessary SQL sentences to the correct Agent installation.
  • sqlUpdateFile : file with necessary SQL sentences to the correct Agent update.
  • logoFile : logo image file, with the same format like all the others in Osmius (29×20 pixels).
  • binaryFiles : Zip file with all necessary files to the correct agent execution.

The OsmiusPluginAgent class is close similar to TestPlugin, but we have added some methods to manage the correct agent installation/upgrade in the Osmius console.

class OsmiusPluginAgent extends OsmiusPluginBase {
   OsmiusResponse execute(Connection conn, ClassLoader classLoader, Locale locale, String version,
                          String workingDir, String messageID) {
      def messages = ResourceBundle.getBundle("org_osmius_plugins_OsmiusPluginAgent", locale, classLoader)
      def pluginXML =  new XmlSlurper().parseText(new File(classLoader.getResource("plugin.xml").toURI()).text)
      String pluginVersion = pluginXML.idnVersion
      String pluginName = pluginXML.idnPlugin
      OsmiusResponse response = new OsmiusResponse(false, new Message("PLG-00000", locale.getLanguage(), messages.getString("PLG-00000")));
      NodeChild xmlagent = new XmlSlurper().parseText(new File(classLoader.getResource("osmiusPluginAgent.xml").toURI()).text)
      try {
         if (checkConsoleVersion(version)) { // First: Check version

            int msgID = getMesageID(messageID);

            switch (msgID) {
               case -1: // First Time : messageID null -> -1
                  def state = getStatePluginVersion(conn, pluginName, pluginVersion)
                  switch (state) {
                     case State.SAME_VERSION: // ERROR: OsmiusPluginAgent is already installed
                        response.setError(true);
                        response.setMessage(new Message("PLG-01001", locale.getLanguage(), messages.getString("PLG-01001")))
                        break
                     case State.MINOR_VERSION: // ERROR: Trying to install a previous version
                        response.setError(true);
                        response.setMessage(new Message("PLG-01002", locale.getLanguage(), messages.getString("PLG-01002")))
                        break
                    case State.NOT_INSTALLED: // NO ERROR - INFO Message to install version
                       response.setError(false);
                       response.setMessage(new Message("PLG-02001", locale.getLanguage(),
                          xmlagent.typeAgent.toString() + " " + messages.getString("PLG-02001") + " " +
                                  xmlagent.typePlatforms.toString()))
                       break
                     case State.MAYOR_VERSION: // NO ERROR - INFO Message to install new version
                        response.setError(false);
                        response.setMessage(new Message("PLG-02002", locale.getLanguage(),
                          xmlagent.typeAgent.toString() + " " + messages.getString("PLG-02002") + " " +
                                  xmlagent.typePlatforms.toString()))
                        break
                  }
                  break
               case 2001: // Install New Agent
                  conn.autoCommit = false;

                  try  {
                    File sqlfile = new File(workingDir + "/" + xmlagent.sqlNewFile.toString())

                    executeSqlFile(conn, response, sqlfile)

                    insertBinariesAgent(conn, response, workingDir, xmlagent)

                    insertLogoAgent(conn, response, workingDir, xmlagent)

                    conn.commit()

                  } catch (Exception e) {
                    conn.rollback()
                    response.setError(true)
                    response.setMessage(new Message("PLG-00001", locale.getLanguage(), messages.getString("PLG-00001")
                              + e.toString()))

                    return response
                  }

                  response.setError(false);
                  response.setMessage(new Message("PLG-00000", locale.getLanguage(), messages.getString("PLG-00000")))

                  break

              case 2002: // Update Agent
                conn.autoCommit = false;

                try  {
                  File sqlfile = new File(workingDir + "/" + xmlagent.sqlUpdateFile.toString())

                  executeSqlFile(conn, response, sqlfile)

                  insertBinariesAgent(conn, response, workingDir, xmlagent)

                  insertLogoAgent(conn, response, workingDir, xmlagent)

                  conn.commit()

                } catch (Exception e) {
                  conn.rollback()
                  response.setError(true)
                  response.setMessage(new Message("PLG-00001", locale.getLanguage(), messages.getString("PLG-00001")
                          + e.toString()))

                  return response
                }

                response.setError(false);
                response.setMessage(new Message("PLG-00000", locale.getLanguage(), messages.getString("PLG-00000")))

                break

               default:
                break
            }
         } else { // ERROR : This plugin can not be installed on this Console version
            response.setError(true);
            response.setMessage(new Message("PLG-01000", locale.getLanguage(), messages.getString("PLG-01000")
                    + version))
            return response
         }
      } catch (Exception e) {
          response.setError(true)
          response.setMessage(new Message("PLG-00001", locale.getLanguage(), messages.getString("PLG-00001")
                 + e.toString()))
          return response
      }

      return response;
   }

   boolean checkConsoleVersion(String version) {
      boolean value = true
      if (version < "v10.04") { //Only works with v10.04
         value = false
      }
      return value
   }

   State getStatePluginVersion(Connection conn, String pluginName, String pluginVersion) {
      State value = State.NOT_INSTALLED

      def version = getDBPluginVersion(conn, pluginName)
      if (version == "") { // No plugin installed
         value = State.NOT_INSTALLED
      } else if (version == pluginVersion) {
         value = State.SAME_VERSION
      } else if (pluginVersion < version) {
         value = State.MINOR_VERSION
      } else if (pluginVersion > version) {
         value = State.MAYOR_VERSION
      }
      return value
   }

   void insertBinariesAgent(Connection conn, OsmiusResponse response, String workingDir, NodeChild xmlagent) {

      Sql sql = new Sql(conn)

      String [] binaries = xmlagent.binaryFiles.toString().split(",")

      byte[] bytesarr

      String typAgent = xmlagent.typeAgent.toString();

      binaries.each { binary ->
        String typPlatform = binary.substring(binary.indexOf("_") + 1,binary.indexOf("."));
        bytesarr = (new File(workingDir + "/" + binary)).readBytes();
        sql.executeUpdate("update osm_typplatform_typagent_d set BIN_AGENT = ? where typ_agent = ? and typ_platform = ?",
                [bytesarr,typAgent,typPlatform])
      }

    }

    void insertLogoAgent(Connection conn, OsmiusResponse response, String workingDir, NodeChild xmlagent) {
      File source = new File(workingDir + "/" + xmlagent.logoFile.toString())
      File destination = new File(workingDir + "/../../images/" + xmlagent.logoFile.toString())
      copyFile(source,destination)
    }

    void copyFile(File source, File destination) {
      def reader = source.newReader()
      destination.withWriter {writer ->
         writer << reader
      }
      reader.close()
    }

    void executeSqlFile(Connection conn, OsmiusResponse response, File sqlfile) {

      Sql sql = new Sql(conn)
      String sqlexec = ""
      String line = ""

      sqlfile.withReader { reader ->
        while (null != (line = reader.readLine())) {
          if (line.size() == 0 || line[0] == '-')
            continue;
          sqlexec = sqlexec + " " + line
          if (sqlexec[sqlexec.size()-1] == ';') {
            sqlexec = sqlexec.trim()
            String [] words = sqlexec.split(" ")
            if (0 == words[0].compareToIgnoreCase("update")) {
              sql.executeUpdate(sqlexec)
            }
            else
              sql.execute(sqlexec)

            sqlexec = ""
          }
        }
      }
   }
}
 
en/desarrollo/plugins.txt · Last modified: 2010/12/22 13:22 (external edit)
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki