Commit f6105c81 authored by Dele Olajide's avatar Dele Olajide

NodeJs plugin for Openfire

parent 7d61ef13
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>NodeJs Plugin Changelog</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
H2 {
font-size : 10pt;
font-weight : bold;
padding-left : 1em;
}
A:hover {
text-decoration : none;
}
H1 {
font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE {
font-family : courier new;
font-size : 100%;
}
</style>
</head>
<body>
<h1>
NodeJs Plugin Changelog
</h1>
<p><b>0.0.1</b> -- May 14, 2014</p>
<ul>
<li>Initial release. </li>
</ul>
</body>
</html>
<?xml version="1.0" encoding="UTF-8" ?>
<plugin>
<author>igniterealtime.org</author>
<class>org.ifsoft.nodejs.openfire.PluginImpl</class>
<description>Integrates NodeJs Applications with Openfire.</description>
<licenseType>Apache 2.0</licenseType>
<minServerVersion>3.8.2</minServerVersion>
<name>NodeJ</name>
<version>0.0.1</version>
<adminconsole>
<tab id="tab-server">
<sidebar id="siderbar-nodejs"
name="${plugin.title}">
<item id="nodejs-settings"
name="${plugin.title}"
description="${plugin.title.description}"
url="nodejs.jsp"/>
</sidebar>
</tab>
</adminconsole>
</plugin>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>NodeJs Plugin Readme</title>
<style type="text/css">
BODY {
font-size : 100%;
}
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em;
}
H2 {
font-size : 10pt;
font-weight : bold;
}
A:hover {
text-decoration : none;
}
H1 {
font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
TT {
font-family : courier new;
font-weight : bold;
color : #060;
}
PRE {
font-family : courier new;
font-size : 100%;
}
#datatable TH {
color : #fff;
background-color : #2A448C;
text-align : left;
}
#datatable TD {
background-color : #FAF6EF;
}
#datatable .name {
background-color : #DCE2F5;
}
</style>
</head>
<body>
<h1>
NodeJs Plugin Readme
</h1>
<h2>Overview</h2>
<p>
NodeJs Plugin for Openfire to enable integration between NodeJs applications and Openfire.
</p>
<h2>Known Issues</h2>
<p>
</p>
<h2>Installation</h2>
<ol>
<li>Copy the nodejs.jar file to the OPENFIRE_HOME/plugins directory.</li>
<li>Restart Openfire.</li>
<li>Configure the admin properties page.</li>
</ol>
<h2>Configuration</h2>
Under Server settings -> NodeJs tab you can configure the folder for the nodejs applications.
<h2>How to use</h2>
<p>
<p/>
</body>
</html>
plugin.title=NodeJs
plugin.title.description=NodeJs Applications from Openfire
config.page.title=NodeJs Settings Page
config.page.configuration.path=NodeJs Applications Path
config.page.configuration.save.title=Save Settings
config.page.configuration.submit=Save
config.page.configuration.restart.warning=Changes to any of these parameters requires a restart of Openfire.
config.page.configuration.node.process=NodeJs Process
config.page.configuration.node.path=Path
config.page.configuration.node.home=Home
package org.ifsoft.nodejs.openfire;
import java.net.*;
import java.io.*;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NodeThread implements Runnable {
private static final Logger Log = LoggerFactory.getLogger(NodeThread.class);
private Thread thread = null;
private Process nodeProcess = null;
private BufferedReader input = null;
public NodeThread()
{
}
public void start(String path, File dir) {
stopThread();
try {
nodeProcess = Runtime.getRuntime().exec(path, null, dir);
Log.info("Started Node");
input = new BufferedReader (new InputStreamReader(nodeProcess.getInputStream()));
Log.info("Started Node Console Reader");
} catch (Exception e) {
Log.info("Started Node exception " + e);
}
// All ok: start a receiver thread
thread = new Thread(this);
thread.start();
}
public void run() {
Log.info("Start run()");
// Get events while we're alive.
while (thread != null && thread.isAlive()) {
try {
String line = input.readLine();
while (line != null) {
Log.info("Node: " + line);
line = input.readLine();
}
Thread.sleep(500);
} catch (Throwable t) {
}
}
}
public void stop() {
Log.info("Stopped Node");
nodeProcess.destroy();
stopThread();
}
public void stopThread() {
Log.info("In stopThread()");
// Keep a reference such that we can kill it from here.
Thread targetThread = thread;
thread = null;
// This should stop the main loop for this thread.
// Killing a thread on a blcing read is tricky.
// See also http://gee.cs.oswego.edu/dl/cpj/cancel.html
if ((targetThread != null) && targetThread.isAlive()) {
targetThread.interrupt();
try {
// Wait for it to die
targetThread.join(500);
}
catch (InterruptedException ignore) {
}
// If current thread refuses to die,
// take more rigorous methods.
if (targetThread.isAlive()) {
// Not preferred but may be needed
// to stop during a blocking read.
targetThread.stop();
// Wait for it to die
try {
targetThread.join(500);
}
catch (InterruptedException ignore) {
}
}
Log.info("Stopped thread alive=" + targetThread.isAlive());
}
}
}
/**
* $Revision $
* $Date $
*
* Copyright (C) 2005-2010 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ifsoft.nodejs.openfire;
import java.io.File;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import org.jitsi.util.OSUtils;
public class PluginImpl implements Plugin, PropertyEventListener
{
private static final Logger Log = LoggerFactory.getLogger(PluginImpl.class);
private String pluginDirectoryPath = null;
private HashMap<String, NodeThread> scripts = new HashMap<String, NodeThread>();
private ExecutorService executor;
private String nodeExePath = null;
public void destroyPlugin()
{
PropertyEventDispatcher.removeListener(this);
try {
for (NodeThread script : scripts.values())
{
script.stop();
}
executor.shutdown();
}
catch (Exception e) {
//Log.error("NodeJs destroyPlugin ", e);
}
}
public void initializePlugin(final PluginManager manager, final File pluginDirectory)
{
PropertyEventDispatcher.addListener(this);
pluginDirectoryPath = JiveGlobals.getProperty("org.ifsoft.nodejs.openfire.path", JiveGlobals.getHomeDirectory() + File.separator + "nodejs");
checkNatives(pluginDirectory);
if (nodeExePath != null)
{
executor = Executors.newCachedThreadPool();
executor.submit(new Callable<Boolean>()
{
public Boolean call() throws Exception {
try {
List<String> properties = JiveGlobals.getPropertyNames();
for (String propertyName : properties)
{
String propertyValue = JiveGlobals.getProperty(propertyName);
executeScript(propertyName, propertyValue);
}
}
catch (Exception e) {
Log.error("NodeJs initializePluginn", e);
}
return true;
}
});
}
}
public String getPath()
{
return pluginDirectoryPath;
}
private void checkNatives(File pluginDirectory)
{
File nodeFolder = new File(pluginDirectoryPath);
if(!nodeFolder.exists())
{
Log.info("initializePlugin home " + pluginDirectory);
nodeFolder.mkdirs();
}
try
{
String suffix = null;
if(OSUtils.IS_LINUX32)
{
suffix = "linux-32";
}
else if(OSUtils.IS_LINUX64)
{
suffix = "linux-64";
}
else if(OSUtils.IS_WINDOWS32)
{
suffix = "win-32";
}
else if(OSUtils.IS_WINDOWS64)
{
suffix = "win-64";
}
else if(OSUtils.IS_MAC)
{
suffix = "osx-64";
}
if (suffix != null)
{
nodeExePath = pluginDirectory.getAbsolutePath() + File.separator + "native" + File.separator + suffix + File.separator + "node";
File file = new File(nodeExePath);
file.setReadable(true, true);
file.setWritable(true, true);
file.setExecutable(true, true);
Log.info("checkNatives node executable path " + nodeExePath);
} else {
Log.error("checkNatives unknown OS " + pluginDirectory.getAbsolutePath());
}
}
catch (Exception e)
{
Log.error(e.getMessage(), e);
}
}
private void executeScript(String scriptPropertyName, String scriptPropertyValue)
{
try {
if (scriptPropertyName.indexOf("js.") == 0 && scriptPropertyName.indexOf(".path") != scriptPropertyName.length() - 5)
{
String scriptPath = scriptPropertyValue;
String scriptHomePath = JiveGlobals.getProperty(scriptPropertyName + ".path", pluginDirectoryPath);
Log.info("executeScript executable path " + scriptPath + " " + scriptHomePath);
NodeThread nodeThread = new NodeThread();
nodeThread.start(nodeExePath + " " + scriptPath, new File(scriptHomePath));
scripts.put(scriptPropertyName, nodeThread);
}
} catch (Throwable t) {
Log.error("Error running NodeJ Scripts ", t);
}
}
//-------------------------------------------------------
//
//
//
//-------------------------------------------------------
public void propertySet(String property, Map params)
{
if (property.indexOf("js.") == 0 && property.indexOf(".path") != property.length() - 5)
{
String value = (String)params.get("value");
if (scripts.containsKey(property))
{
NodeThread script = scripts.get(property);
script.stop();
}
executeScript(property, value);
}
}
public void propertyDeleted(String property, Map<String, Object> params)
{
if (scripts.containsKey(property))
{
NodeThread script = scripts.remove(property);
script.stop();
}
}
public void xmlPropertySet(String property, Map<String, Object> params) {
}
public void xmlPropertyDeleted(String property, Map<String, Object> params) {
}
}
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jitsi.util;
/**
* Utility fields for OS detection.
*
* @author Sebastien Vincent
* @author Lubomir Marinov
*/
public class OSUtils
{
/** <tt>true</tt> if architecture is 32 bit. */
public static final boolean IS_32_BIT;
/** <tt>true</tt> if architecture is 64 bit. */
public static final boolean IS_64_BIT;
/** <tt>true</tt> if OS is Android */
public static final boolean IS_ANDROID;
/** <tt>true</tt> if OS is Linux. */
public static final boolean IS_LINUX;
/** <tt>true</tt> if OS is Linux 32-bit. */
public static final boolean IS_LINUX32;
/** <tt>true</tt> if OS is Linux 64-bit. */
public static final boolean IS_LINUX64;
/** <tt>true</tt> if OS is MacOSX. */
public static final boolean IS_MAC;
/** <tt>true</tt> if OS is MacOSX 32-bit. */
public static final boolean IS_MAC32;
/** <tt>true</tt> if OS is MacOSX 64-bit. */
public static final boolean IS_MAC64;
/** <tt>true</tt> if OS is Windows. */
public static final boolean IS_WINDOWS;
/** <tt>true</tt> if OS is Windows 32-bit. */
public static final boolean IS_WINDOWS32;
/** <tt>true</tt> if OS is Windows 64-bit. */
public static final boolean IS_WINDOWS64;
/** <tt>true</tt> if OS is Windows Vista. */
public static final boolean IS_WINDOWS_VISTA;
/** <tt>true</tt> if OS is Windows 7. */
public static final boolean IS_WINDOWS_7;
/** <tt>true</tt> if OS is Windows 8. */
public static final boolean IS_WINDOWS_8;
/** <tt>true</tt> if OS is FreeBSD. */
public static final boolean IS_FREEBSD;
static
{
// OS
String osName = System.getProperty("os.name");
if (osName == null)
{
IS_ANDROID = false;
IS_LINUX = false;
IS_MAC = false;
IS_WINDOWS = false;
IS_WINDOWS_VISTA = false;
IS_WINDOWS_7 = false;
IS_WINDOWS_8 = false;
IS_FREEBSD = false;
}
else if (osName.startsWith("Linux"))
{
String javaVmName = System.getProperty("java.vm.name");
if ((javaVmName != null) && javaVmName.equalsIgnoreCase("Dalvik"))
{
IS_ANDROID = true;
IS_LINUX = false;
}
else
{
IS_ANDROID = false;
IS_LINUX = true;
}
IS_MAC = false;
IS_WINDOWS = false;
IS_WINDOWS_VISTA = false;
IS_WINDOWS_7 = false;
IS_WINDOWS_8 = false;
IS_FREEBSD = false;
}
else if (osName.startsWith("Mac"))
{
IS_ANDROID = false;
IS_LINUX = false;
IS_MAC = true;
IS_WINDOWS = false;
IS_WINDOWS_VISTA = false;
IS_WINDOWS_7 = false;
IS_WINDOWS_8 = false;
IS_FREEBSD = false;
}
else if (osName.startsWith("Windows"))
{
IS_ANDROID = false;
IS_LINUX = false;
IS_MAC = false;
IS_WINDOWS = true;
IS_WINDOWS_VISTA = (osName.indexOf("Vista") != -1);
IS_WINDOWS_7 = (osName.indexOf("7") != -1);
IS_WINDOWS_8 = (osName.indexOf("8") != -1);
IS_FREEBSD = false;
}
else if (osName.startsWith("FreeBSD"))
{
IS_ANDROID = false;
IS_LINUX = false;
IS_MAC = false;
IS_WINDOWS = false;
IS_WINDOWS_VISTA = false;
IS_WINDOWS_7 = false;
IS_WINDOWS_8 = false;
IS_FREEBSD = true;
}
else
{
IS_ANDROID = false;
IS_LINUX = false;
IS_MAC = false;
IS_WINDOWS = false;
IS_WINDOWS_VISTA = false;
IS_WINDOWS_7 = false;
IS_WINDOWS_8 = false;
IS_FREEBSD = false;
}
// arch i.e. x86, amd64
String osArch = System.getProperty("sun.arch.data.model");
if(osArch == null)
{
IS_32_BIT = true;
IS_64_BIT = false;
}
else if (osArch.indexOf("32") != -1)
{
IS_32_BIT = true;
IS_64_BIT = false;
}
else if (osArch.indexOf("64") != -1)
{
IS_32_BIT = false;
IS_64_BIT = true;
}
else
{
IS_32_BIT = false;
IS_64_BIT = false;
}
// OS && arch
IS_LINUX32 = IS_LINUX && IS_32_BIT;
IS_LINUX64 = IS_LINUX && IS_64_BIT;
IS_MAC32 = IS_MAC && IS_32_BIT;
IS_MAC64 = IS_MAC && IS_64_BIT;
IS_WINDOWS32 = IS_WINDOWS && IS_32_BIT;
IS_WINDOWS64 = IS_WINDOWS && IS_64_BIT;
}
/**
* Allows the extending of the <tt>OSUtils</tt> class but disallows
* initializing non-extended <tt>OSUtils</tt> instances.
*/
protected OSUtils()
{
}
}
<%@ page import="java.util.*" %>
<%@ page import="org.ifsoft.nodejs.openfire.*" %>
<%@ page import="org.jivesoftware.openfire.*" %>
<%@ page import="org.jivesoftware.util.*" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
<%
boolean update = request.getParameter("update") != null;
String errorMessage = null;
// Get handle on the plugin
PluginImpl plugin = (PluginImpl) XMPPServer.getInstance().getPluginManager().getPlugin("nodejs");
if (update)
{
String path = request.getParameter("path");
JiveGlobals.setProperty("org.ifsoft.nodejs.openfire.path", path);
}
%>
<html>
<head>
<title><fmt:message key="config.page.title" /></title>
<meta name="pageID" content="nodejs-settings"/>
</head>
<body>
<% if (errorMessage != null) { %>
<div class="error">
<%= errorMessage%>
</div>
<br/>
<% } %>
<div class="jive-table">
<form action="nodejs.jsp" method="post">
<p>
<table class="jive-table" cellpadding="0" cellspacing="0" border="0" width="100%">
<thead>
<tr>
<th colspan="2"><fmt:message key="config.page.title"/></th>
</tr>
</thead>
<tbody>
<tr>
<td align="left" width="150">
<fmt:message key="config.page.configuration.path"/>
</td>
<td><input type="text" size="50" maxlength="100" name="path"
value="<%= JiveGlobals.getProperty("org.ifsoft.nodejs.openfire.path", plugin.getPath()) %>">
</td>
</tr>
</tbody>
</table>
</p>
<p>
<table class="jive-table" cellpadding="0" cellspacing="0" border="0" width="100%">
<thead>
<tr>
<th colspan="2"><fmt:message key="config.page.configuration.save.title"/></th>
</tr>
</thead>
<tbody>
<tr>
<th colspan="2"><input type="submit" name="update" value="<fmt:message key="config.page.configuration.submit" />"><fmt:message key="config.page.configuration.restart.warning"/></th>
</tr>
</tbody>
</table>
</p>
</form>
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<thead>
<tr>
<th nowrap><fmt:message key="config.page.configuration.node.process" /></th>
<th nowrap><fmt:message key="config.page.configuration.node.path" /></th>
<th nowrap><fmt:message key="config.page.configuration.node.home" /></th>
</tr>
</thead>
<tbody>
<%
List<String> properties = JiveGlobals.getPropertyNames();
for (String n : properties)
{
if (n.indexOf("js.") == 0 && n.indexOf(".path") != n.length() - 5)
{
String v = JiveGlobals.getProperty(n);
String p = StringUtils.replace(StringUtils.escapeHTMLTags(v), "\n", "");
String h = JiveGlobals.getProperty(n + ".path", JiveGlobals.getProperty("org.ifsoft.nodejs.openfire.path", plugin.getPath()));
%>
<tr>
<td>
<div class="hidebox" style="width:200px;">
<span title="<%= StringUtils.escapeForXML(n) %>">
<%= StringUtils.escapeHTMLTags(n) %>
</span>
</div>
</td>
<td>
<div class="hidebox" style="width:300px;">
<% if (JiveGlobals.isPropertyEncrypted(n) ||
JiveGlobals.isPropertySensitive(n)) { %>
<span style="color:#999;"><i>hidden</i></span>
<% } else { %>
<span title="<%= ("".equals(v) ? "&nbsp;" : v) %>"><%= ("".equals(v) ? "&nbsp;" : v) %></span>
<% } %>
</div>
</td>
<td>
<div class="hidebox" style="width:300px;">
<% if (JiveGlobals.isPropertyEncrypted(n) ||
JiveGlobals.isPropertySensitive(n)) { %>
<span style="color:#999;"><i>hidden</i></span>
<% } else { %>
<span title="<%= ("".equals(p) ? "&nbsp;" : p) %>"><%= ("".equals(p) ? "&nbsp;" : p) %></span>
<% } %>
</div>
</td>
</tr>
<%
}
}
%>
</tbody>
</table>
</div>
</body>
</html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment