Creating your own Rest Plugin ( extending REST API )
The Rest Plugin feature helps you to extending the REST API.
You can create your own Form Validator
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 of "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 into the package com.openkm.plugin.rest because the application plugins system will try to load it from there.
Do not miss the tag @PluginImplementation otherwise the application plugin system won't be able to use the class.
More information at Register a new plugin.
Method description
Method | Type | Description |
---|---|---|
executePlugin | String |
The method executes a REST plugin an return an object. |
Example of REST plugin implementation
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 what returns file
The sample below goes in combination of REST webservice "/rest/plugin/executeGetPluginReturnFile" method.
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);
}
}
Objects declaration
The method executionPlugin returns an Object. This object will be processed - marshall - by OpenKM. Basic types like String, Integer, etc. can be directly used, but for complex objects you need to use annotation on classes.
Marshall and unmarshall strategies:
- The result of the executed method is always an String. Internally the method converts the complex objects to JSON.
- The result of the executed mehod is a complex Object.
String scenario
From the plugin side - server side - you must convert the Object to JSON:
return new Gson().toJson(someObject)
From the cliend side you must convert JSON String to Object:
// value contains the returned String value by the REST call
SomeObject someObject = new Gson().fromJson(value, SomeObject.class);
Complex Object scenario
You can use existing OpenKM classes like Document, Folder, Record, Mail among others, because theses clases have already the annotation.
Use the anotation ( in the sample below the object will be marshalled with name "mail" ):
@XmlRootElement(name = "mail")
Example of complex classes:
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();
}
}
Advanced REST sample
Because this sample uses low-level API, you should always ask OpenKM IT staff before using it on production for understanding the benefits and restrictions of this kind of implementation.
The next sample is a project that uses low-level API implementation for quick upload and set metadata at the same time. A sample comes with plugin implementation and client plugin test.
If you have a huge uploading process and are looking for performance this is a good approach.
- Download the sample project sample-rest.zip.