Joget DX 8 Stable Released
The stable release for Joget DX 8 is now available, with a focus on UX and Governance.
Table of Contents |
---|
This article demonstrate the implementation of the web socker support for plugin.
Figure 1:
Figure 2:
Result
This article is a guide for implementing web socket support function into a Joget application.
The following is an example of implementing the WebSocket feature inside a radio form element. It showcases one of the ways to create a WebSocket plugin and the code belongs to the plugin class.
Info |
---|
There are 4 key web socket methods that you are required to pay attention to: public void onOpen(Session session) public void onMessage(String message, Session session) public void onClose(Session session) |
Code Block | ||
---|---|---|
| ||
package org.joget;
import java.io.IOException;
import java.util.Map;
import javax.websocket.Session;
import org.joget.apps.app.service.AppPluginUtil;
import org.joget.apps.app.service.AppUtil;
import org.joget.apps.form.lib.Radio;
import org.joget.apps.form.model.FormBuilderPalette;
import org.joget.apps.form.model.FormData;
import org.joget.apps.form.model.FormRow;
import org.joget.apps.form.model.FormRowSet;
import org.joget.apps.form.service.FormUtil;
import org.joget.commons.util.LogUtil;
import org.joget.plugin.base.PluginWebSocket;
import org.joget.workflow.model.service.WorkflowUserManager;
public class WebSocketPlugin extends Radio implements PluginWebSocket {
private final static String MESSAGE_PATH = "message/form/WebSocketPlugin";
@Override
public String getName() {
return "WebSocketPlugin";
}
@Override
public String getVersion() {
return "5.0.0";
}
@Override
public String getClassName() {
return getClass().getName();
}
@Override
public String getLabel() {
//support i18n
return AppPluginUtil.getMessage("org.joget.WebSocketPlugin.pluginLabel", getClassName(), MESSAGE_PATH);
}
@Override
public String getDescription() {
//support i18n
return AppPluginUtil.getMessage("org.joget.WebSocketPlugin.pluginDesc", getClassName(), MESSAGE_PATH);
}
@Override
public String getPropertyOptions() {
return AppUtil.readPluginResource(getClass().getName(), "/properties/form/" + getName() + ".json", null, true, MESSAGE_PATH);
}
@Override
public FormRowSet formatData(FormData formData) {
FormRowSet rowSet = null;
// get value
String id = getPropertyString(FormUtil.PROPERTY_ID);
if (id != null) {
String value = FormUtil.getElementPropertyValue(this, formData);
if (value != null) {
// set value into Properties and FormRowSet object
FormRow result = new FormRow();
result.setProperty(id, value);
rowSet = new FormRowSet();
rowSet.add(result);
}
}
return rowSet;
}
@Override
public String renderTemplate(FormData formData, Map dataModel) {
String template = "webSocketPlugin.ftl";
WorkflowUserManager wum = (WorkflowUserManager) AppUtil.getApplicationContext().getBean("workflowUserManager");
String username = wum.getCurrentUsername();
dataModel.put("username", username);
String html = FormUtil.generateElementHtml(this, formData, template, dataModel);
return html;
}
@Override
public String getFormBuilderTemplate() {
return "<label class='label'>" + getLabel() + "</label>";
}
@Override
public String getFormBuilderCategory() {
return FormBuilderPalette.CATEGORY_CUSTOM;
}
@Override
public void onOpen(Session session) {
try {
session.getBasicRemote().sendText("Connection established");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onMessage(String message, Session session) {
try {
session.getBasicRemote().sendText("Server received: " + message);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onClose(Session session) {
LogUtil.info(getClassName(), "Webscoket connection closed");
}
@Override
public void onError(Session session, Throwable throwable) {
LogUtil.error(getClassName(), throwable, "");
}
public boolean isEnabled() {
if ("true".equalsIgnoreCase(getPropertyString("enableWebsocket"))) {
return true;
} else {
return false;
}
}
} |
A FTL file is required for rendering the HTML content for the WebSocket plugin, you may copy the following code as a starting template.
Info | ||
---|---|---|
The endpoint is specified at this line:
The following 4 functions are event handlers that handles different WebSocket Events : ws.onopen = function(event) |
Code Block | ||
---|---|---|
| ||
<div class="form-cell" ${elementMetaData!}>
<label class="label">
${element.properties.label} <span class="form-cell-validator">${decoration}</span>
<#if error??>
<span class="form-error-message">${error}</span>
</#if>
</label>
<#if (element.properties.enableWebsocket! == 'true')>
<input id="isEnabled" name="isEnabled" type="hidden" />
</#if>
<#if (element.properties.readonly! == 'true' && element.properties.readonlyLabel! == 'true') >
<div class="form-cell-value"><span>${value!?html}</span></div>
<input id="${elementParamName!}" name="${elementParamName!}" type="hidden" value="${value!?html}" />
<#else>
<input type="text" id="messageInput" placeholder="Enter message">
<button id="sendButton">Send</button>
<button id="closeButton">Close</button><br>
<div id='output'></div>
</#if>
<script>
$(document).ready(function() {
$("#sendButton").off("click");
$("#closeButton").off("click");
if ($("#isEnabled").length > 0) {
const ws = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "${request.contextPath}/web/socket/plugin/org.joget.WebSocketPlugin");
ws.onopen = function(event) {
console.log(event);
$("#output").append('Connection opened with timeStamp: ' + event.timeStamp + '<br/>');
$("#sendButton").on("click", function(){
const message = $("#messageInput").val();
//send message to endpoint
ws.send(message);
$("#output").append("${username} send " + message + '<br/>');
$("#messageInput").val("");
return false;
});
$("#closeButton").on("click", function(){
if (ws.readyState === WebSocket.OPEN) {
//close the endpoint connection
ws.close();
}
$("#sendButton").hide();
$("#closeButton").hide();
return false;
});
};
ws.onmessage = function(event) {
$("#output").append(event.data + '<br/>');
};
ws.onclose = function(event) {
$("#output").append('Connection closed with timeStamp: ' + event.timeStamp + '<br/>');
$("#output").append('WebSocket closed<br/>');
};
ws.onError = function(event) {
$("#output").append("Error: " + event.data + '<br/>');
};
} else {
$("#output").html('WebSocket is not enable.<br>');
}
});
</script>
<div style="clear:both;"></div>
</div>
|
This sample plugin code is available at https://github.com/jogetoss/sample-web-socket-plugin. JogetOSS is a community-led team for open source software related to the Joget no-code/low-code application platform. Projects under JogetOSS are community-driven and community-supported, and you are welcome to contribute to the projects.Figure 3: