Skip to content

Creating your own Rest Plugin ( extending REST API )

You can create your own REST Plugin.

Conditions:

  • The new REST class must implement the “RestPlugin” interface.
  • The new REST class must be declared under the package “com.openkm.plugin.rest”.
  • The new REST class must be annotated with@PluginImplementation”.
  • The new REST class must extend “BasePlugin”.

REST interface:

package com.openkm.plugin.rest;
import net.xeoh.plugins.base.Plugin;
import java.io.InputStream;
import java.util.Map;
/**
* RestPlugin
*/
public interface RestPlugin extends Plugin {
Object executePlugin(Map<String, String> parameters, InputStream is) throws Exception;
}

The new class must be located in the package com.openkm.plugin.rest because the application plugin system will try to load it from there.

Method Type Description
executePlugin Object The method executes a REST plugin and returns an object.
package com.openkm.plugin.rest;
import com.openkm.plugin.BasePlugin;
import net.xeoh.plugins.base.annotations.PluginImplementation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.Map;
/**
* Sample rest plugin
*/
@PluginImplementation
public class TestRestPlugin extends BasePlugin implements RestPlugin {
private static Logger log = LoggerFactory.getLogger(TestRestPlugin.class);
@Override
public Object executePlugin(Map<String, String> parameters, InputStream is) throws Exception {
log.debug("executePlugin({})", parameters);
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("className=").append(this.getClass().getCanonicalName());
for (String key : parameters.keySet()) {
sb.append(", " + key + "=").append(parameters.get(key));
}
return sb.toString();
}
}

Example of REST plugin implementation that returns a file

Section titled “Example of REST plugin implementation that returns a file”
package com.openkm.plugin.rest;
import com.openkm.bean.Document;
import com.openkm.module.db.DbDocumentModule;
import com.openkm.plugin.BasePlugin;
import com.openkm.util.PathUtils;
import net.xeoh.plugins.base.annotations.PluginImplementation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.io.InputStream;
import java.util.Map;
/**
* Sample rest plugin
*/
@PluginImplementation
public class TestGetDocumentRestPlugin extends BasePlugin implements RestPlugin {
private static Logger log = LoggerFactory.getLogger(TestGetDocumentRestPlugin.class);
@Autowired
private DbDocumentModule dbDocumentModule;
@Autowired
private PathUtils pathUtils;
@Override
public Object executePlugin(Map<String, String> parameters, InputStream is) throws Exception {
log.debug("executePlugin({})", parameters);
String docId = parameters.get("docId");
boolean inline = parameters.containsKey("inline");
Document doc = dbDocumentModule.getProperties(null, docId);
String mimeType = doc.getMimeType();
String fileName = pathUtils.getName(doc.getPath());
InputStream isContent = dbDocumentModule.getContent(null, docId, false);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", mimeType);
// inline true when you want to embedded the content into
if (inline) {
responseHeaders.add("Content-disposition", "inline; filename=\"" + fileName + "\"");
} else {
responseHeaders.add("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
}
responseHeaders.setContentLength(doc.getActualVersion().getSize());
InputStreamResource inputStreamResource = new InputStreamResource(isContent);
log.debug("TestGetDocumentRestPlugin: [BINARY]");
return new ResponseEntity<>(inputStreamResource, responseHeaders, HttpStatus.OK);
}
}

The method executionPlugin returns an Object. This object will be processed - marshalled - by OpenKM. Basic types like String, Integer, etc. can be used directly, but for complex objects you need to use annotations on classes.

Marshalling and unmarshalling strategies:

  • The result of the executed method is always a String. Internally, the method converts complex objects to JSON.
  • The result of the executed method is a complex object.

From the plugin side - server side - you must convert the object to JSON:

return new Gson().toJson(someObject)

From the client side you must convert the JSON string to an object:

// value contains the returned String value by the REST call
SomeObject someObject = new Gson().fromJson(value, SomeObject.class);

You can use existing OpenKM classes like Document, Folder, Record, Mail among others, because these classes already have the annotations.

Return a list of Activities:

package com.openkm.ws.rest.util;
import com.openkm.db.bean.Activity;
import java.util.ArrayList;
import java.util.List;
public class ActivityList {
List<Activity> activities = new ArrayList<>();
private int totalElements;
public List<Activity> getActivities() {
return activities;
}
public void setActivities(List<Activity> activities) {
this.activities = activities;
}
public int getTotalElements() {
return totalElements;
}
public void setTotalElements(int totalElements) {
this.totalElements = totalElements;
}
}

Complex object:

package com.openkm.bean;
public class Record extends Parent {
private static final long serialVersionUID = 1L;
public static final String TYPE = "okm:record";
public static final String NAME = "okm:name";
private boolean locked;
private LockInfo lockInfo;
private String title;
private boolean hasLinks;
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
public LockInfo getLockInfo() {
return lockInfo;
}
public void setLockInfo(LockInfo lockInfo) {
this.lockInfo = lockInfo;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean hasLinks() {
return hasLinks;
}
public void setHasLinks(boolean hasLinks) {
this.hasLinks = hasLinks;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("uuid=").append(uuid);
sb.append(", parent=").append(parent);
sb.append(", path=").append(path);
sb.append(", permissions=").append(permissions);
sb.append(", created=").append(created == null ? null : created.getTime());
sb.append(", subscribed=").append(subscribed);
sb.append(", subscriptors=").append(subscriptors);
sb.append(", keywords=").append(keywords);
sb.append(", categories=").append(categories);
sb.append(", notes=").append(notes);
sb.append(", locked=").append(locked);
sb.append(", lockInfo=").append(lockInfo);
sb.append(", title=").append(title);
sb.append(", nodeClass=").append(getNodeClass());
sb.append(", nodeClassChildren=").append(getNodeClassChildren());
sb.append(", dispositionCurrentStage=").append(getDispositionCurrentStage());
sb.append("}");
return sb.toString();
}
}

The next sample is a project that uses a low-level API implementation for quick uploads and setting metadata at the same time. The sample comes with a plugin implementation and a client plugin test.

If you have a large upload process and are looking for better performance, this is a good approach.