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;
 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;
import java.util.logging.Logger
We will declare the log variable in our main class
 private Logger log = Logger.getLogger(getClass().getName());
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
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.