Commit 4235cb26 authored by Roman S's avatar Roman S

Merge pull request #281 from PGoski/master

Get count of unread messages in REST API plugin & added new callback plugin which call a url if user is offline
parents e387da54 a300bcea
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Callback on offline 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>
Callback on offline Plugin Changelog
</h1>
<p><b>1.0</b> -- August 16, 2015</p>
<ul>
<li>Initial release. </li>
</ul>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<!-- Main plugin class -->
<class>com.fotsum.CallbackOnOffline</class>
<name>CallbackOnOffline</name>
<description>Url is called when recipient is offline</description>
<author>Pavel Goski</author>
<version>1.0</version>
<date>08/16/2015</date>
<minServerVersion>2.3.0</minServerVersion>
</plugin>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Callback on offline 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>
Callback on offline Plugin Readme
</h1>
<h2>Overview</h2>
<p>
The plugin loads url from 'plugin.callback_on_offline.url' property, adds 'to' & 'from' parameters and executes GET request. The request is async.
Sample link: http://localhost:8080/user/offline/callback/url?from=1%40fotsum.com&to=2%40fotsum.com
</p>
<p>
If something don't work, set "plugin.callback_on_offline.debug" property to true and check the debug log.
</p>
</body>
</html>
package com.fotsum;
import org.jivesoftware.openfire.PresenceManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import java.io.File;
import java.util.UUID;
import java.util.concurrent.Future;
public class CallbackOnOffline implements Plugin, PacketInterceptor {
private static final Logger Log = LoggerFactory.getLogger(CallbackOnOffline.class);
private boolean debug;
private String url;
private String token;
private InterceptorManager interceptorManager;
private UserManager userManager;
private PresenceManager presenceManager;
private Client client;
public void initializePlugin(PluginManager pManager, File pluginDirectory) {
debug = JiveGlobals.getBooleanProperty("plugin.callback_on_offline.debug", false);
if (debug) {
Log.debug("initialize CallbackOnOffline plugin. Start.");
}
interceptorManager = InterceptorManager.getInstance();
presenceManager = XMPPServer.getInstance().getPresenceManager();
userManager = XMPPServer.getInstance().getUserManager();
client = ClientBuilder.newClient();
url = getProperty("plugin.callback_on_offline.url", "http://localhost:8080/user/offline/callback/url");
token = getProperty("plugin.callback_on_offline.token", UUID.randomUUID().toString());
// register with interceptor manager
interceptorManager.addInterceptor(this);
if (debug) {
Log.debug("initialize CallbackOnOffline plugin. Finish.");
}
}
private String getProperty(String code, String defaultSetValue) {
String value = JiveGlobals.getProperty(code, null);
if (value == null || value.length() == 0) {
JiveGlobals.setProperty(code, defaultSetValue);
value = defaultSetValue;
}
return value;
}
public void destroyPlugin() {
// unregister with interceptor manager
interceptorManager.removeInterceptor(this);
if (debug) {
Log.debug("destroy CallbackOnOffline plugin.");
}
}
public void interceptPacket(Packet packet, Session session, boolean incoming,
boolean processed) throws PacketRejectedException {
if (processed
&& incoming
&& packet instanceof Message
&& packet.getTo() != null) {
Message msg = (Message) packet;
if (msg.getType() != Message.Type.chat) {
return;
}
try {
JID to = packet.getTo();
User userTo = userManager.getUser(to.getNode());
boolean available = presenceManager.isAvailable(userTo);
if (debug) {
Log.debug("intercepted message from {} to {}, recipient is available {}", packet.getFrom().toBareJID(), to.toBareJID(), available);
}
if (!available) {
JID from = packet.getFrom();
WebTarget target = client.target(url)
.queryParam("token", token)
.queryParam("from", from.toBareJID())
.queryParam("to", to.toBareJID());
if (debug) {
Log.debug("sending request to url='{}'", target);
}
Future<Response> responseFuture = target.request().async().get();
if (debug) {
try {
Response response = responseFuture.get();
Log.debug("got response status url='{}' status='{}'", target, response.getStatus());
} catch (Exception e) {
Log.debug("can't get response status url='{}'", target, e);
}
}
}
} catch (UserNotFoundException e) {
}
}
}
}
......@@ -44,6 +44,11 @@
REST API Plugin Changelog
</h1>
<p><b>1.1.3</b> -- August 15th, 2015</p>
<ul>
<li>Added: get count of users unread messages</li>
</ul>
<p><b>1.1.2</b> -- August 4th, 2015</p>
<ul>
<li>Added: CORS to all endpoints</li>
......
......@@ -5,8 +5,8 @@
<name>REST API</name>
<description>Allows administration over a RESTful API.</description>
<author>Roman Soldatow</author>
<version>1.1.2</version>
<date>08/04/2015</date>
<version>1.1.3</version>
<date>08/15/2015</date>
<minServerVersion>3.9.0</minServerVersion>
<adminconsole>
......
package org.jivesoftware.openfire.plugin.rest.controller;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.XMPPServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* The Class MsgArchiveController.
*/
public class MsgArchiveController {
private static final Logger Log = LoggerFactory.getLogger(MsgArchiveController.class);
/** The Constant INSTANCE. */
public static final MsgArchiveController INSTANCE = new MsgArchiveController();
/** The server. */
private XMPPServer server;
private static final String USER_MESSAGE_COUNT = "select COUNT(1) from ofMessageArchive a " +
"join ofPresence p on (a.sentDate > p.offlineDate) " +
"WHERE a.toJID = ? AND p.username = ?";
/**
* Gets the single instance of MsgArchiveController.
*
* @return single instance of MsgArchiveController
*/
public static MsgArchiveController getInstance() {
return INSTANCE;
}
/**
* Instantiates a new user service controller.
*/
private MsgArchiveController() {
server = XMPPServer.getInstance();
}
/**
* Returns the total number of messages that haven't been delivered to the user.
*
* @return the total number of user unread messages.
*/
public int getUnReadMessagesCount(JID jid) {
int messageCount = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(USER_MESSAGE_COUNT);
pstmt.setString(1, jid.toBareJID());
pstmt.setString(2, jid.getNode());
rs = pstmt.executeQuery();
if (rs.next()) {
messageCount = rs.getInt(1);
}
} catch (SQLException sqle) {
Log.error(sqle.getMessage(), sqle);
} finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return messageCount;
}
}
package org.jivesoftware.openfire.plugin.rest.entity;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* The Class MsgArchiveEntity.
*/
@XmlRootElement(name = "archive")
public class MsgArchiveEntity {
@XmlElement
String jid;
/**
* unread messages count
*/
@XmlElement
int count;
public MsgArchiveEntity() {
}
public MsgArchiveEntity(String jid, int count) {
this.jid = jid;
this.count = count;
}
}
......@@ -82,6 +82,8 @@ public class JerseyWrapper extends ServletContainer {
prc.getClasses().add(SessionService.class);
prc.getClasses().add(RESTExceptionMapper.class);
prc.getClasses().add(MsgArchiveService.class);
}
/**
......
package org.jivesoftware.openfire.plugin.rest.service;
import org.jivesoftware.openfire.plugin.rest.controller.MsgArchiveController;
import org.jivesoftware.openfire.plugin.rest.entity.MsgArchiveEntity;
import org.jivesoftware.openfire.plugin.rest.exceptions.ServiceException;
import org.xmpp.packet.JID;
import javax.annotation.PostConstruct;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("restapi/v1/archive/messages/unread/{jid}")
public class MsgArchiveService {
private MsgArchiveController archive;
@PostConstruct
public void init() {
archive = MsgArchiveController.getInstance();
}
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public MsgArchiveEntity getUnReadMessagesCount(@PathParam("jid") String jidStr) throws ServiceException {
JID jid = new JID(jidStr);
int msgCount = archive.getUnReadMessagesCount(jid);
return new MsgArchiveEntity(jidStr, msgCount);
}
}
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