wiki:PluginDevelopmentGuide

Version 9 (modified by jri, 12 years ago) (diff)

Migrations introduction

Plugin Development Guide

DeepaMehta is made to be extensible by 3rd-party developers. Developers extend DeepaMehta by developing plugins (resp. "modules" resp. "applications" which is all synonymous).

Build DeepaMehta from source

The best way to develop DeepaMehta plugins is to build DeepaMehta from source first. This way you get a hot-deploy environment, that is DeepaMehta redeploys your plugin automatically once you compile it. This is very handy while plugin development.

Requirements:

  • Java 6 (newer versions might work as well, older versions do not work)
  • Maven 3 (older versions do not work)
  • Git

Build DeepaMehta from source:

$ git clone git://github.com/jri/deepamehta.git
$ cd deepamehta
$ mvn install -P all

This builds all components of the DeepaMehta Standard Distribution and installs them in your local Maven repository. You'll see a lot of information logged, cumulating in:

...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 53.515s
...

The plugin turn-around cycle

This section illustrates how to begin a plugin project, how to build and how to deploy a plugin, and how to redeploy the plugin once you made changes in its source code. In other words, this section illustrates the plugin development turn-around cycle.

Let's start with a very simple plugin called DeepaMehta 4 Tagging. This plugin will just create a new topic type called Tag. Once the plugin is activated the topic type will appear in the DeepaMehta Webclient's Create menu, so you can create tag topics and associate them with arbitrary topics. And you will be able to fulltext search for tags.

Developing a plugin whose only purpose is to provide new topic type definitions requires no Java or JavaScript? coding. All is declarative, mainly in JSON format.

Of course the topic type could be created interactively as well, by using the DeepaMehta Webclient's type editor. However, being packaged as a plugin means you can distribute it. When other DeepaMehta users install your plugin they can use your type definitions.

Begin a plugin project

From the developer's view a DeepaMehta plugin is just a directory on your hard disc. The directory can have an arbitrary name and exist at an arbitrary location. By convention the plugin directory begins with dm4- as it is aimed to the DeepaMehta 4 platform. The directory content adheres to a certain directory structure and file name conventions. The files are text files (xml, json, properties, java, js, css) and resources like images.

To create the DeepaMehta 4 Tagging plugin setup a directory structure as follows:

dm4-tagging/
    pom.xml
    src/
        main/
            resources/
                migrations/
                    migration1.json
                plugin.properties

Create the file pom.xml with this content:

<project>
    <modelVersion>4.0.0</modelVersion>

    <name>DeepaMehta 4 Tagging</name>
    <groupId>org.mydomain.dm4</groupId>
    <artifactId>tagging</artifactId>
    <version>0.1-SNAPSHOT</version>
    <packaging>bundle</packaging>

    <parent>
        <groupId>de.deepamehta</groupId>
        <artifactId>deepamehta-plugin-parent</artifactId>
        <version>4.1.1-SNAPSHOT</version>
    </parent>
</project>

Create the file migration1.json:

{
    topic_types: [
        {
            value: "Tag",
            uri: "domain.tagging.tag",
            data_type_uri: "dm4.core.text",
            index_mode_uris: ["dm4.core.fulltext"],
            view_config_topics: [
                {
                    type_uri: "dm4.webclient.view_config",
                    composite: {
                        dm4.webclient.show_in_create_menu: true
                    }
                }
            ]
        }
    ]
}

Create the file plugin.properties:

requiredPluginMigrationNr=1
importModels=de.deepamehta.webclient

Setup for Hot-Deployment

In order to let DeepaMehta hot-deploy the plugin you must include it in DeepaMehta's hot-deployment list.

In DeepaMehta's pom.xml: add the plugin's target directory (here: /home/myhome/deepamehta-dev/dm4-tagging/target) to the felix.fileinstall.dir property's CDATA section. Important: don't forget to append a comma to the previous line:

<project>
    ...
    <felix.fileinstall.dir>
        <![CDATA[
            ${project.basedir}/modules/dm4-core/target,
            ${project.basedir}/modules/dm4-webservice/target,
            ${project.basedir}/modules/dm4-webclient/target,
            ...
            ${project.basedir}/modules/dm4-storage-neo4j/target,
            /home/myhome/deepamehta-dev/dm4-tagging/target
        ]]>
    </felix.fileinstall.dir>
    ...
</project>

Now start DeepaMehta. In the directory deepamehta (where you've build):

$ mvn pax:run

This starts DeepaMehta in development mode, that is with hot-deployment activated. You'll see a lot of information logged, cumulating with:

...
Apr 6, 2013 11:21:20 PM de.deepamehta.core.impl.PluginManager checkAllPluginsActivated
INFO: ### Bundles total: 32, DeepaMehta plugins: 16, Activated: 16
Apr 6, 2013 11:21:20 PM de.deepamehta.core.impl.PluginManager activatePlugin
INFO: ########## All Plugins Activated ##########
Apr 6, 2013 11:21:20 PM de.deepamehta.plugins.webclient.WebclientPlugin allPluginsActive
INFO: ### Launching webclient (url="http://localhost:8080/de.deepamehta.webclient/")
...

Then a browser windows opens automatically and displays the DeepaMehta Webclient.

The terminal is now occupied by the Gogo shell. Press the return key some times and you'll see its g! prompt.

Type the lb command to get the list of activated bundles:

g! lb

The output looks like this:

START LEVEL 6
   ID|State      |Level|Name
    0|Active     |    0|System Bundle (3.2.1)
   ...
   14|Active     |    5|DeepaMehta 4 Help (4.1.1.SNAPSHOT)
   15|Active     |    5|DeepaMehta 4 Topicmaps (4.1.1.SNAPSHOT)
   16|Active     |    5|DeepaMehta 4 Webservice (4.1.1.SNAPSHOT)
   17|Active     |    5|DeepaMehta 4 Files (4.1.1.SNAPSHOT)
   18|Active     |    5|DeepaMehta 4 Geomaps (4.1.1.SNAPSHOT)
   19|Active     |    5|DeepaMehta 4 Storage - Neo4j (4.1.1.SNAPSHOT)
   20|Active     |    5|DeepaMehta 4 Core (4.1.1.SNAPSHOT)
   21|Active     |    5|DeepaMehta 4 Access Control (4.1.1.SNAPSHOT)
   22|Active     |    5|DeepaMehta 4 Webclient (4.1.1.SNAPSHOT)
   23|Active     |    5|DeepaMehta 4 Webbrowser (4.1.1.SNAPSHOT)
   24|Active     |    5|DeepaMehta 4 Type Search (4.1.1.SNAPSHOT)
   25|Active     |    5|DeepaMehta 4 Workspaces (4.1.1.SNAPSHOT)
   26|Active     |    5|DeepaMehta 4 Notes (4.1.1.SNAPSHOT)
   27|Active     |    5|DeepaMehta 4 Type Editor (4.1.1.SNAPSHOT)
   28|Active     |    5|DeepaMehta 4 Contacts (4.1.1.SNAPSHOT)
   29|Active     |    5|DeepaMehta 4 Facets (4.1.1.SNAPSHOT)
   30|Active     |    5|DeepaMehta 4 File Manager (4.1.1.SNAPSHOT)
   31|Active     |    5|DeepaMehta 4 Icon Picker (4.1.1.SNAPSHOT)

The DeepaMehta 4 Tagging plugin does not yet appear in that list as it is not yet build.

Build the plugin

In another terminal:

$ cd dm4-tagging
$ mvn clean package

This builds the plugin. After some seconds you'll see:

...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.988s
...

Once build, DeepaMehta hot-deploys the plugin automatically. In the terminal where you've started DeepaMehta the logging informs you about plugin activation:

Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl readConfigFile
INFO: Reading config file "/plugin.properties" for plugin "DeepaMehta 4 Tagging"
Apr 6, 2013 11:38:40 PM de.deepamehta.core.osgi.PluginActivator start
INFO: ========== Starting plugin "DeepaMehta 4 Tagging" ==========
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl createPluginServiceTrackers
INFO: Tracking plugin services for plugin "DeepaMehta 4 Tagging" ABORTED -- no consumed services declared
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl addService
INFO: Adding DeepaMehta 4 core service to plugin "DeepaMehta 4 Tagging"
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl addService
INFO: Adding Web Publishing service to plugin "DeepaMehta 4 Tagging"
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl registerWebResources
INFO: Registering Web resources of plugin "DeepaMehta 4 Tagging" ABORTED -- no Web resources provided
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl registerRestResources
INFO: Registering REST resources of plugin "DeepaMehta 4 Tagging" ABORTED -- no REST resources provided
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl registerRestResources
INFO: Registering provider classes of plugin "DeepaMehta 4 Tagging" ABORTED -- no provider classes provided
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl addService
INFO: Adding Event Admin service to plugin "DeepaMehta 4 Tagging"
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginManager activatePlugin
INFO: ----- Activating plugin "DeepaMehta 4 Tagging" -----
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl createPluginTopicIfNotExists
INFO: Installing plugin "DeepaMehta 4 Tagging" in the database
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.MigrationManager runPluginMigrations
INFO: Running 1 migrations for plugin "DeepaMehta 4 Tagging" (migrationNr=0, requiredMigrationNr=1)
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.MigrationManager$MigrationInfo readMigrationConfigFile
INFO: Reading migration config file "/migrations/migration1.properties" ABORTED -- file does not exist
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.MigrationManager runMigration
INFO: Running migration 1 of plugin "DeepaMehta 4 Tagging" (runMode=ALWAYS, isCleanInstall=true)
Apr 6, 2013 11:38:40 PM de.deepamehta.core.util.DeepaMehtaUtils readMigrationFile
INFO: Reading migration file "/migrations/migration1.json"
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.MigrationManager runMigration
INFO: Completing migration 1 of plugin "DeepaMehta 4 Tagging"
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.MigrationManager runMigration
INFO: Updating migration number (1)
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.AttachedTopic update
INFO: Updating topic 2690 (new topic (id=-1, uri="", typeUri="dm4.core.plugin_migration_nr", value="1", composite={}))
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.AttachedDeepaMehtaObject updateSimpleValue
INFO: ### Changing simple value of topic 2690 from "0" -> "1"
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl registerListeners
INFO: Registering listeners of plugin "DeepaMehta 4 Tagging" at DeepaMehta 4 core service ABORTED -- no listeners implemented
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginImpl registerPluginService
INFO: Registering OSGi service of plugin "DeepaMehta 4 Tagging" ABORTED -- no OSGi service provided
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginManager activatePlugin
INFO: ----- Activation of plugin "DeepaMehta 4 Tagging" complete -----
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginManager checkAllPluginsActivated
INFO: ### Bundles total: 33, DeepaMehta plugins: 17, Activated: 17
Apr 6, 2013 11:38:40 PM de.deepamehta.core.impl.PluginManager activatePlugin
INFO: ########## All Plugins Activated ##########
Apr 6, 2013 11:38:40 PM de.deepamehta.plugins.webclient.WebclientPlugin allPluginsActive
INFO: ### Launching webclient (url="http://localhost:8080/de.deepamehta.webclient/") ABORTED -- already launched
...

When you type again lb in the DeepaMehta terminal you'll see the DeepaMehta 4 Tagging plugin now appears in the list of activated bundles:

START LEVEL 6
   ID|State      |Level|Name
    0|Active     |    0|System Bundle (3.2.1)
   ...
   30|Active     |    5|DeepaMehta 4 File Manager (4.1.1.SNAPSHOT)
   31|Active     |    5|DeepaMehta 4 Icon Picker (4.1.1.SNAPSHOT)
   32|Active     |    5|DeepaMehta 4 Tagging (0.1.0.SNAPSHOT)

Try out the plugin

Now you can try out the plugin. In the DeepaMehta Webclient login as user "admin" and leave the password field empty. The Create menu appears and when you open it you'll see the new type Tag listed. Thus, you can create tags now. Additionally you can associate tags to your content topics, search for tags, and navigate along the tag associations, just as you do with other topics.

The result so far: the DeepaMehta 4 Tagging plugin provides a new topic type definition or, in other words: a data model. All the active operations on the other hand like create, edit, search, delete, associate, and navigate are provided by the DeepaMehta Webclient at a generic level, and are applicable to your new topic type as well.

Redeploy the plugin

Once you've made any changes to the plugin files, you have to build the plugin again. Just like before in the plugin terminal:

$ mvn clean package

Once building is complete the changed plugin is redeployed automatically. You'll notice activity in the DeepaMehta terminal:

Apr 8, 2013 1:10:40 AM de.deepamehta.core.osgi.PluginActivator stop
INFO: ========== Stopping plugin "DeepaMehta 4 Tagging" ==========
Apr 8, 2013 1:10:40 AM de.deepamehta.core.impl.PluginImpl removeService
INFO: Removing DeepaMehta 4 core service from plugin "DeepaMehta 4 Tagging"
Apr 8, 2013 1:10:40 AM de.deepamehta.core.impl.PluginImpl removeService
INFO: Removing Web Publishing service from plugin "DeepaMehta 4 Tagging"
Apr 8, 2013 1:10:40 AM de.deepamehta.core.impl.PluginImpl removeService
INFO: Removing Event Admin service from plugin "DeepaMehta 4 Tagging"
...
...
Apr 8, 2013 1:10:44 AM de.deepamehta.core.osgi.PluginActivator start
INFO: ========== Starting plugin "DeepaMehta 4 Tagging" ==========
...
...
Apr 8, 2013 1:10:44 AM de.deepamehta.core.impl.PluginManager activatePlugin
INFO: ----- Activating plugin "DeepaMehta 4 Tagging" -----
Apr 8, 2013 1:10:44 AM de.deepamehta.core.impl.PluginImpl createPluginTopicIfNotExists
INFO: Installing plugin "DeepaMehta 4 Tagging" in the database ABORTED -- already installed
Apr 8, 2013 1:10:44 AM de.deepamehta.core.impl.MigrationManager runPluginMigrations
INFO: Running migrations for plugin "DeepaMehta 4 Tagging" ABORTED -- everything up-to-date (migrationNr=1)
...
...
Apr 8, 2013 1:10:44 AM de.deepamehta.core.impl.PluginManager activatePlugin
INFO: ----- Activation of plugin "DeepaMehta 4 Tagging" complete -----
Apr 8, 2013 1:10:44 AM de.deepamehta.core.impl.PluginManager checkAllPluginsActivated
INFO: ### Bundles total: 33, DeepaMehta plugins: 17, Activated: 17
Apr 8, 2013 1:10:44 AM de.deepamehta.core.impl.PluginManager activatePlugin
INFO: ########## All Plugins Activated ##########
Apr 8, 2013 1:10:44 AM de.deepamehta.plugins.webclient.WebclientPlugin allPluginsActive
INFO: ### Launching webclient (url="http://localhost:8080/de.deepamehta.webclient/") ABORTED -- already launched
...

In contrast to the initial build of the plugin you can recognize some differences in this log:

  • The old version of the plugin currently deployed is stopped.
  • The new version of the plugin is deployed (that is started and activated) right away.
  • The plugin is not installed again in the database as already done while initial build.
  • The migration is not run again as already done while initial build.

To ensure the DeepaMehta Webclient is aware of the changed plugin press the browser's reload button.

Stopping DeepaMehta

To stop DeepaMehta, in the Gogo shell type:

g! stop 0

This stops all bundles, shuts down the webserver, and the database.

Migrations

A migration is a sequence of database operations that is executed exactly once in the lifetime of a particular DeepaMehta installation. You as a developer are responsible for equipping your plugin with the required migrations. Migrations serve several purposes:

  1. Define the plugin's data model. That is, storing new topic type definitions and association type definitions in the database. E.g. a Books plugin might define the Book, Title, and Author types.
  1. A newer version of your plugin might extend or modify the data model defined by the previous version of your plugin. The migration of the updated plugin change the stored type definitions and transforms existing content if necessary.
  1. The application logic of a newer version of your plugin changes in a way it is not compatible anymore with the existing database content. The migration must transform the existing content then.

So, the purpose expressed in points 2. and 3. is to make your plugin upgradable. That is, keeping existing database content in-snyc with the plugin logic. By providing the corresponding migrations you make your plugin compatible with the previous plugin version.

Attachments