May 032014
 

Some months ago, I wrote a post of how to start creating a plugin in DeepaMehta, it was basically to show, the use of migrations to create new topic types in a permanent way, in your DeepaMehta instance.
It was the first step to create a Calendar plugin for DeepaMehta, but since to create both client side and server side for that plugin would be quite difficult task as a first contact with DeepaMehta, I decided to do a couple of things first.

One was to actually write a casual user guide of how DeepaMehta can be used, that has deepen my understanding of how to use it, how it works, what I miss, etc.

On its way, one of the things that I miss is the possibility to import and export topicmaps. So since import-export feature works more at a server side, I thought it would be good to first focus on the server side, with a bit of client side, to get familiar with DM development framework.

The good thing is that this part is already documented in DeepaMehta  plugin developers documentation 🙂 so what I’ll try to do is write down my use case with the import-export plugin.

To start the plugin main file must be located directly in the plugin’s src/main/java/, so the first thing to do is to create this structure, then it will have to be followed by a specific tree structure and the plugin name(as a convention, must end with Plugin). So the first thing is to figure out this directory structure.

One thing that I forgot to say, is that actually the first thing to do when creating a plugin is to define the pom.xml file. Following the guide, the initial pom.xml will look something like

<?xml version="1.0" encoding="UTF-8"?>


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <name>DeepaMehta 4 Import Export </name>
  <groupId>net.abriraqui.dm4 </groupId>
  <artifactId>dm43-SNAPSHOT-import-export</artifactId>
  <version>0.1-SNAPSHOT</version>
  <packaging>bundle </packaging>

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

</project>

The important thing to see is the groupId, where we are defining the unique namespace for our plugin,net.abriraqui.dm4, and the artifactId, where we are defining the context where is created, that is DeepaMehta version (4.3) SNAPSHOT , the development version, followed by the name of the plugin, import-export.

We will build a correspondent directory structure inside src/main/java  that will me net/abriraqui/dm4/importexport  , importexport is the name of the plugin that in the directory structure, by convention, won’t have a dash in between.

Once you’ve created the directory structure, you create your plugin java file that should be called, ImportExportPlugin.java .

So as in the dev guide says, the plugin package is net.abriraqui.dm4.importexport and the plugin main class is ImportExportPlugin

A plugin main file is a Java class that is derived from de.deepamehta.core.osgi.PluginActivator. The smallest possible plugin main file looks like this

package net.abriraqui.dm4.importexport;

import de.deepamehta.core.osgi.PluginActivator;
public class ImportExportPlugin extends PluginActivator {
}


3 things are illustrated here:

  • The plugin should be packaged in an unique namespace.
  • The PluginActivator class needs to be imported.
  • The plugin main class must be derived from PluginActivator and must be public.

so now, in the pom.xml we will need to tell maven where is our plugin and how is it called.

We will specify the dependency by adding a dependency element (you can directly see it in the original file) in the pom.xml file and a build element where you will have the Bundle-Activator element to specify where is your plugin and how is it called.

Ok, now have our basis settle, lets see what is that we want to do. We can write it as a user story :

I want to select a topicmap and then be able to export that topicmap into a json file.

For that we need, to define an uri where the export action will take place. We can define our plugin uri in  “/import-export”, so for our export action we can set the uri at “import-export/export”.

In this case, what we will provide is a RESTful web service. So checking the DM plugin development documentation:

To make your plugin service RESTful you must:

  •     Annotate the plugin main class with @Path to anchor the plugin service in URI space.
  •     Annotate the plugin main class with @Consumes and @Produces to declare the supported HTTP request and response media types. You can use these annotations also at a particular service method to override the class-level defaults.
  •     Annotate each service method with one of @GET, @POST, @PUT, or @DELETE to declare the HTTP method that will invoke that service method.
  •     Annotate each service method with @Path to declare the URI template that will invoke that service method. The URI template can contain parameters, notated with curly braces {…}.
  •     Annotate service method parameters with @PathParam to map URI template parameters to service method parameters.

Let’s see how to implement it :

The main class has to be annotated with @Path, and we’ve said that the uri, which is equivalent to the path, that we wanted was “/import-export” so it should look like :

@Path("/import-export")
public class ImportExportPlugin extends PluginActivator {
....
}

Now, we need to actually define our “export” action, so we need the method inside our main class, and we need to pass one parameter, the topicmapId, so that we know which topicmap to export. Our method should look something like this

public void export (long topicmapId){
...
}

We will write this method a bit later, for the moment we focus on how to provide the RESTful service. So each service method has to be annotated with the HTTP method that will invoke the service method, in our case it will be a @POST service. So, taking into account that, we have to define the uri where the export is taking place, our code should look like

@POST
@Path("/export")
public void export(long topicmapId) { 
...
}

so the overview of how should our code look like to provide a service is

package net.abriraqui.dm4.importexport;
@Path("/import-export")
public class ImportExportPlugin extends PluginActivator {
    @POST
    @Path("/export")
    public void export(long topicmapId) { 
    }
}

Lets add all the bits and pieces that will make this work,  now is just a very basic skeleton. First we are saying that our class extends PluginActivator, so we should access PluginActivator, for that we have to

import de.deepamehta.core.osgi.PluginActivator

then, we will need everything that lets us provide a REST service, the @POST action and the @Path where our resource is.

import javax.ws.rs.POST;
import javax.ws.rs.Path;
The next thing to look at is our export method, we need to get the topicmapId parameter , but where do we get it from? we are going to read it from the cookie provided by DM.The Topicmaps plugin set and maintains “dm4_topicmap_id” cookie. That cookie reflects the topicmap that is currently selected. To check we will print it in the log.
 
public void export (@CookieParam("dm4_topicmap_id") long topicmapId){
 log.info("Exporting topicmap #########" + topicmapId;
...
 }

In order to be able to read the cookie we need to

import javax.ws.rs.CookieParam;
and to write into the log, we need to declare the variable log after importing the Logger class.
import java.util.logging.Logger

We will declare the log variable in our main class

 private Logger log = Logger.getLogger(getClass().getName());
So now your plugin file should look like
package net.abriraqui.dm4.importexport;

import de.deepamehta.core.osgi.PluginActivator;

import java.util.logging.Logger;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.CookieParam;

@Path("/import-export")
public class ImportExportPlugin extends PluginActivator {
    private Logger log = Logger.getLogger(getClass().getName());
  
  // Service implementation //

    @POST
    @Path("/export")
    public void export(@CookieParam("dm4_topicmap_id") long topicmapId) {
      log.info("Exporting topicmap #########" + topicmapId);
    }
}

If in the console, you build your plugin with

$ mvn clean package
your plugin should be working and once you export the map in the webclient,  an amazing message will be printed in your log “Exporting topicmap XXX” … exciting , right? 🙂
To continue, lets see how to get the current topicmap, so that after we are able to export it to a JSON file. In order to success, we will need to consume the topicmap service, which means, as is explained in the DM plugin development documentation :
“Your plugin can consume the services provided by other plugins. To do so your plugin must get hold of the service object of the other plugin. Through the service object your plugin can call all the service methods declared in the other’s plugin service interface. “
What we are looking for is to see how to get the topicmap. For that we need to get hold of the TopicmapsService and if we take a look at it, we see  it provides the getTopicmap method, which will return an object TopicmapViewmodel. Cool!! just what we needed :-), so we import both
import de.deepamehta.plugins.topicmaps.service.TopicmapsService;
import de.deepamehta.plugins.topicmaps.model.TopicmapViewmodel;

import de.deepamehta.core.service.PluginService;
import de.deepamehta.core.service.annotation.ConsumesService;

we need ConsumesService and PluginService, because ….
so we need to add two methods at the end of our main class

 // Hook implementation //
    
@Override  @ConsumesService("de.deepamehta.plugins.topicmaps.service.TopicmapsService")
public void serviceArrived(PluginService service) {
topicmapsService = (TopicmapsService) service;
}

@Override
public void serviceGone(PluginService service) {
topicmapsService = null;
}

Now lets get the topicmap. First in the main class we need to  declare a variable with the TopicmapsService

private TopicmapsService topicmapsService;

then inside our export method we declare the variable topicmap, where topicmap that we want to export will be stored

public void export(@CookieParam("dm4_topicmap_id") long topicmapId) {
      log.info("Exporting topicmap #########" + topicmapId);
      TopicmapViewmodel topicmap = topicmapsService.getTopicmap(topicmapId);

}

Well, amazing but we already have the whole topicmap :-)))) … so there is a last step missing, to write it down into a JSON file. To be able to write files we need to access to classes Writer and FileWriter.

import java.io.Writer;
import java.io.FileWriter;

and to save it in JSON format we need

import org.codehaus.jettison.json.JSONObject;

Now for writing a json file with a name like “topicmap-1323.json” into your disk, DM provides and easy way to do it, by just calling the method toJSON to the topicmap instance.

 public void export(@CookieParam("dm4_topicmap_id") long topicmapId) {
    log.info("Exporting topicmap #########" + topicmapId);
    TopicmapViewmodel topicmap = topicmapsService.getTopicmap(topicmapId);
    Writer writer = new FileWriter("topicmap-" + topicmapId + ".json");
    JSONObject json = topicmap.toJSON();
    json.write(writer);
    writer.close();
}

Since we are keeping things veeeeeeery simple, the file will be stored at the runner directory placed in DM root directory.

If you build your plugin, probably it will failed, at least that was my case, it gave a couple of ExceptionErrors that should be catched as you can check the code on the github repository where the source code is ;).

And yes, once you’ve done that,you will be able to generate a pretty json file with your topicmap info :-)). There is just one small thing missing, from where do you do it?

We have taken for granted that we will export topicmaps through DM webclient, so for that, we have to enable the export option that we’ve written in the client side. Which is explained in the next post.

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)