Commit 823668d0 authored by Holger Bergunde's avatar Holger Bergunde Committed by holger.bergunde

remote roster is now known as gojara

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@12952 b35dd754-fafc-0310-a699-88a17e54d16e
parent 15073cb3
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>GoJara 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>
GoJara Plugin Changelog
</h1>
<p><b>1.1 Alpha</b> -- Jan 6, 2012</p>
<ul>
<li>Added feature to limit gateways to specific user group</li>
<li>Capture packets to create statistics</li>
<li>Added live logging</li>
<li>Renamed to GoJara</li>
</ul>
<p><b>1.0 Alpha</b> -- Dec 12, 2011</p>
<ul>
<li>Initial release. </li>
</ul>
</body>
</html>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<!-- Main plugin class -->
<class>org.jivesoftware.openfire.plugin.RemoteRosterPlugin</class>
<name>GoJara</name>
<description>ProtoXEP-xxxx: Remote Roster Management support</description>
<author>Holger Bergunde and Daniel Henninger</author>
<version>1.1.0 Alpha</version>
<date>01/06/2012</date>
<databaseKey>gojara</databaseKey>
<databaseVersion>0</databaseVersion>
<minServerVersion>3.7.0</minServerVersion>
<!-- Admin console entries -->
<adminconsole>
<tab id="tab-server">
<sidebar id="sidebar-server-settings">
<item id="remoteRoster" name="${rr.summary.title}"
url="rr-main.jsp"
description="${rr.summary.title}" />
</sidebar>
</tab>
</adminconsole>
</plugin>
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>GoJara 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>
GoJara Plugin Readme
</h1>
<h2>Overview</h2>
<p>
This plugin will implement the proto-XEP, Remote Roster, discussed
<a href="http://jkaluza.fedorapeople.org/remote-roster.html">here</a>.
Basically it's purpose is to allow an external component full
control over the part of a roster it's assigned. For example,
if the AIM transport is at aim.example.org, you can allow that transport
to make whatever modifications it needs without involving the end user.
This is especially useful so that a user does not get flooded with
subscription requests upon registration. This plugin also implements
a few minor extensions that Kraken used to implement for Spark, though
those are optional.
</p>
<h2>Installation</h2>
<p>Copy remoteRoster.jar into the plugins directory of your Openfire installation. The
plugin will then be automatically deployed. To upgrade to a new version, copy the new
remoteRoster.jar file over the existing file.</p>
<h2>Configuration</h2>
<p>The GoJara plugin can be configured under "Server"-"Server Settings"-"GoJara".</p>
</body>
</html>
\ No newline at end of file
CREATE TABLE ofGojaraStatistics (
logID bigint(20) NOT NULL AUTO_INCREMENT,
messageDate bigint(20) NOT NULL,
messageType tinytext NOT NULL,
fromJID text NOT NULL,
toJID text NOT NULL,
component text NOT NULL,
PRIMARY KEY (logID)
);
INSERT INTO ofVersion (name, version) VALUES ('gojara', 0);
CREATE TABLE ofGojaraStatistics (
logID Integer Identity NOT NULL,
messageDate bigint(20) NOT NULL,
messageType VARCHAR(255) NOT NULL,
fromJID VARCHAR(255) NOT NULL,
toJID VARCHAR(255) NOT NULL,
component VARCHAR(255) NOT NULL,
PRIMARY KEY (logID)
);
INSERT INTO ofVersion (name, version) VALUES ('gojara', 0);
CREATE TABLE ofGojaraStatistics (
logID bigint(20) NOT NULL AUTO_INCREMENT,
messageDate bigint(20) NOT NULL,
messageType tinytext NOT NULL,
fromJID text NOT NULL,
toJID text NOT NULL,
component text NOT NULL,
PRIMARY KEY (logID)
);
INSERT INTO ofVersion (name, version) VALUES ('gojara', 0);
CREATE TABLE ofGojaraStatistics (
logID bigint(20) NOT NULL AUTO_INCREMENT,
messageDate bigint(20) NOT NULL,
messageType tinytext NOT NULL,
fromJID text NOT NULL,
toJID text NOT NULL,
component text NOT NULL,
PRIMARY KEY (logID)
);
INSERT INTO ofVersion (name, version) VALUES ('gojara', 0);
CREATE TABLE ofGojaraStatistics (
logID bigint(20) NOT NULL AUTO_INCREMENT,
messageDate bigint(20) NOT NULL,
messageType tinytext NOT NULL,
fromJID text NOT NULL,
toJID text NOT NULL,
component text NOT NULL,
PRIMARY KEY (logID)
);
INSERT INTO ofVersion (name, version) VALUES ('gojara', 0);
CREATE TABLE ofGojaraStatistics (
logID bigint(20) NOT NULL AUTO_INCREMENT,
messageDate bigint(20) NOT NULL,
messageType tinytext NOT NULL,
fromJID text NOT NULL,
toJID text NOT NULL,
component text NOT NULL,
PRIMARY KEY (logID)
);
INSERT INTO ofVersion (name, version) VALUES ('gojara', 0);
CREATE TABLE ofGojaraStatistics (
logID bigint(20) NOT NULL AUTO_INCREMENT,
messageDate bigint(20) NOT NULL,
messageType tinytext NOT NULL,
fromJID text NOT NULL,
toJID text NOT NULL,
component text NOT NULL,
PRIMARY KEY (logID)
);
INSERT INTO ofVersion (name, version) VALUES ('gojara', 0);
rr.summary.title=GoJara
\ No newline at end of file
package org.jivesoftware.openfire.plugin;
import java.util.Collection;
import org.jivesoftware.openfire.group.Group;
import org.jivesoftware.openfire.group.GroupManager;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.JID;
public class PermissionManager {
GroupManager _groupManager = GroupManager.getInstance();
public boolean isGatewayLimited(String subdomain)
{
return getGroupForGateway(subdomain).length() > 0;
}
public boolean allowedForUser(String gateway, JID jid)
{
String groupAllowedFor = getGroupForGateway(gateway);
if (groupAllowedFor != null) {
Collection<Group> groups = _groupManager.getGroups(jid);
for (Group gr : groups) {
if (gr.getName().equals(groupAllowedFor))
{
return true;
}
}
}
return false;
}
public String getGroupForGateway(String gateway)
{
return JiveGlobals.getProperty("plugin.remoteroster.permissiongroup."+gateway, "");
}
public void setGroupForGateway(String gateway, String group)
{
JiveGlobals.setProperty("plugin.remoteroster.permissiongroup."+gateway, group);
}
public void removeGatewayLimitation(String gateway)
{
setGroupForGateway(gateway, "");
}
}
package org.jivesoftware.openfire.plugin;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.component.ComponentEventListener;
import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.plugin.interceptor.AbstractInterceptorHandler;
import org.jivesoftware.openfire.plugin.interceptor.GatewayInterceptorHandler;
import org.jivesoftware.openfire.session.ComponentSession;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
public class RemoteRosterPlugin implements Plugin {
private static final Logger Log = LoggerFactory.getLogger(RemoteRosterPlugin.class);
final SessionManager _sessionManager = SessionManager.getInstance();
private Map<String, AbstractInterceptorHandler> _interceptors = new HashMap<String, AbstractInterceptorHandler>();
private static PluginManager pluginManager;
private Set<String> _waitingForIQResponse = new HashSet<String>();
private PropertyEventListener _settingsObserver;
public RemoteRosterPlugin() {
}
public void initializePlugin(PluginManager manager, File pluginDirectory)
{
Log.debug("Starting RemoteRoster Plugin");
pluginManager = manager;
manageExternalComponents();
listenToSettings();
}
private void manageExternalComponents()
{
InternalComponentManager compManager = InternalComponentManager.getInstance();
compManager.addListener(new ComponentEventListener() {
/**
* Check if the unregistered component contains to one of our
* package interceptors
*/
@Override
public void componentUnregistered(JID componentJID)
{
ComponentSession session = _sessionManager.getComponentSession(componentJID.getDomain());
if (session != null && _interceptors.containsKey(session.getExternalComponent().getInitialSubdomain())) {
String initialSubdomain = session.getExternalComponent().getInitialSubdomain();
// Remove it from Map & ComponentManager
removeInterceptor(initialSubdomain);
}
}
/**
* If there is a new external Component, check if it is a gateway
* and add create a package interceptor if it is enabled
*/
@Override
public void componentRegistered(JID componentJID)
{
_waitingForIQResponse.add(componentJID.getDomain());
}
@Override
public void componentInfoReceived(IQ iq)
{
String from = iq.getFrom().getDomain();
// Waiting for this external component sending an IQ response to
// us?
if (_waitingForIQResponse.contains(from)) {
Element packet = iq.getChildElement();
Document doc = packet.getDocument();
List<Node> nodes = Utils.findNodesInDocument(doc, "//disco:identity[@category='gateway']");
// Is this external component a gateway and there is no
// package interceptor for it?
if (nodes.size() > 0 && !_interceptors.containsKey(from)) {
updateInterceptors(from);
}
// We got the IQ, we can now remove it from the set, because
// we are not waiting any more
_waitingForIQResponse.remove(from);
}
}
});
}
private void listenToSettings()
{
_settingsObserver = new RemoteRosterPropertyListener() {
@Override
protected void changedProperty(String prop)
{
updateInterceptors(prop);
}
};
PropertyEventDispatcher.addListener(_settingsObserver);
}
public void destroyPlugin()
{
for (String key : _interceptors.keySet()) {
_interceptors.get(key).stop();
}
PropertyEventDispatcher.removeListener(_settingsObserver);
pluginManager = null;
}
private void updateInterceptors(String componentJID)
{
boolean allowed = JiveGlobals.getBooleanProperty("plugin.remoteroster.jids." + componentJID, false);
if (allowed) {
if (!_interceptors.containsKey(componentJID)) {
createNewPackageIntercetor(componentJID);
}
} else {
if (_interceptors.containsKey(componentJID)) {
removeInterceptor(componentJID);
}
}
}
public String getName()
{
return "remoteRoster";
}
public static PluginManager getPluginManager()
{
return pluginManager;
}
private void removeInterceptor(String initialSubdomain)
{
AbstractInterceptorHandler interceptor = _interceptors.get(initialSubdomain);
if (interceptor != null) {
_interceptors.remove(initialSubdomain);
interceptor.stop();
}
}
private void createNewPackageIntercetor(String initialSubdomain)
{
AbstractInterceptorHandler interceptor = new GatewayInterceptorHandler(initialSubdomain);
_interceptors.put(initialSubdomain, interceptor);
interceptor.start();
}
}
package org.jivesoftware.openfire.plugin;
import java.util.Map;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.util.PropertyEventListener;
public abstract class RemoteRosterPropertyListener implements PropertyEventListener {
@Override
public void xmlPropertySet(String property, Map<String, Object> params)
{
}
@Override
public void xmlPropertyDeleted(String property, Map<String, Object> params)
{
}
@Override
public void propertySet(String property, Map<String, Object> params)
{
if (property.contains("plugin.remoteroster.jids.")) {
changedProperty(property.replace("plugin.remoteroster.jids.", ""));
}
}
@Override
public void propertyDeleted(String property, Map<String, Object> params)
{
String hostname = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
property += "." + hostname;
changedProperty(property.replace("plugin.remoteroster.jids.", ""));
}
protected abstract void changedProperty(String prop);
}
package org.jivesoftware.openfire.plugin;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import org.dom4j.XPath;
public class Utils {
/**
* Search the specified document for Nodes corresponding to the xpath Keep
* in mind that you have to use xmpp namespace for searching
* Predefined namespaces:
* jabber:iq:roster //roster:*
* jabber:iq:register //register:*
* http://jabber.org/protocol/disco#info //disco/*
* e.g
* '//roster:features'
*
* @param doc
* document
* @param xpath
* with roster namespace for searching in query nodes
* @return list of nodes found by xpath expression
*/
@SuppressWarnings("unchecked")
public static List<Node> findNodesInDocument(Document doc, String xpath)
{
Map<String, String> namespaceUris = new HashMap<String, String>();
namespaceUris.put("roster", "jabber:iq:roster");
namespaceUris.put("discoitems", "http://jabber.org/protocol/disco#items");
namespaceUris.put("register", "jabber:iq:register");
namespaceUris.put("disco", "http://jabber.org/protocol/disco#info");
XPath xPath = DocumentHelper.createXPath(xpath);
xPath.setNamespaceURIs(namespaceUris);
return xPath.selectNodes(doc);
}
/**
* Returns the username from the given jid. user.name@jabber.server.org
* returns "user.name"
*
* @param jid
* @return the extracted username as string
*/
public static String getUsernameFromJid(String jid)
{
int firstAtPos = jid.indexOf("@");
return firstAtPos != -1 ? jid.substring(0, firstAtPos) : jid;
}
}
package org.jivesoftware.openfire.plugin.database;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.log4j.Logger;
import org.jivesoftware.database.DbConnectionManager;
public class DatabaseManager {
private static Logger Log = Logger.getLogger(DatabaseManager.class);
private static volatile DatabaseManager _myself;
private static final String COUNT_LOG_ENTRIES = "SELECT count(*) FROM ofGojaraStatistics";
private static final String COUNT_PACKAGES_ODLER = "SELECT count(*) FROM `ofGojaraStatistics` WHERE messageType like ? AND component = ? AND messageDate > ?";
private static final String GET_ALL_LOGS = "SELECT * FROM ofGojaraStatistics ORDER BY logID desc";
// private static final String MOST_ACTIVE = "SELECT toJID, count(logID) AS counter FROM `ofGojaraStatistics` GROUP by toJID ORDER BY counter DESC";
private static final String ADD_NEW_LOG = "INSERT INTO ofGojaraStatistics(messageDate, messageType, fromJID, toJId, component) VALUES(?,?,?,?,?)";
private static final String CLEAN_OLD_DATA = "DELETE FROM `ofGojaraStatistics` WHERE messageDate < ?";
private static final String GET_LOGS_DATE_LIMIT_COMPONENT = "SELECT * FROM `ofGojaraStatistics` WHERE messageDate > ? AND component LIKE ? ORDER BY messageDate DESC LIMIT ?";
private DatabaseManager() {
TimerTask task = new TimerTask() {
@Override
public void run() {
cleanOldLogEntries();
}
};
Timer timer = new Timer();
timer.schedule(task, 2 * 60 * 1000, 2 * 60 * 1000);
}
/**
* Singleton for Databasemanager, because we only need one.
*
* @return the Databasemanager
*/
public static DatabaseManager getInstance() {
if (_myself == null) {
synchronized (DatabaseManager.class) {
if (_myself == null)
_myself = new DatabaseManager();
}
}
return _myself;
}
/**
* Returns a list of LogEntry's ordered by date desc
*
* @param olderThan
* unix timestamp in ms
* @param limit
* num of rows max
* @param component
* the specified subdomain of the logged component
* @return Collection of LogEntry
*/
public Collection<LogEntry> getLogsByDateAndLimit(long olderThan, int limit, String component) {
List<LogEntry> result = new ArrayList<LogEntry>();
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(GET_LOGS_DATE_LIMIT_COMPONENT);
pstmt.setLong(1, olderThan);
pstmt.setString(2, component);
pstmt.setInt(3, limit);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
String from = rs.getString(4);
String to = rs.getString(5);
String type = rs.getString(3);
long date = rs.getLong(2);
LogEntry res = new LogEntry(from, to, type, date);
result.add(res);
}
pstmt.close();
} catch (SQLException sqle) {
Log.error(sqle);
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
return result;
}
public void cleanOldLogEntries() {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(CLEAN_OLD_DATA);
pstmt.setLong(1, System.currentTimeMillis() - 60 * 60 * 1000);
int rows = pstmt.executeUpdate();
Log.debug("Cleaned statistic database. Affected rows: " + rows);
pstmt.close();
} catch (SQLException sqle) {
Log.error(sqle);
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
public void addNewLogEntry(String component, String type, String from, String to) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(ADD_NEW_LOG);
pstmt.setLong(1, System.currentTimeMillis());
pstmt.setString(2, type);
pstmt.setString(3, from);
pstmt.setString(4, to);
pstmt.setString(5, component);
pstmt.executeUpdate();
pstmt.close();
} catch (SQLException sqle) {
Log.error(sqle);
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
public List<String> getAllLogs() {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List<String> _result = new ArrayList<String>();
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(GET_ALL_LOGS);
rs = pstmt.executeQuery();
while (rs.next()) {
String from = rs.getString(4);
String to = rs.getString(5);
String type = rs.getString(3);
String component = rs.getString(6);
Timestamp date = rs.getTimestamp(2);
String res = "From: " + from + " To: " + to + " Type: " + type + " Timestamp: " + date.toString()
+ "Component: " + component;
_result.add(res);
}
}
catch (SQLException sqle) {
Log.error(sqle);
} finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return _result;
}
public int getLogSize() {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(COUNT_LOG_ENTRIES);
rs = pstmt.executeQuery();
rs.next();
return rs.getInt(1);
} catch (SQLException sqle) {
Log.error(sqle);
} finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return 0;
}
public int getPacketCount(String component, Class packetClass) {
return getPacketCountOlderThan(component, packetClass, 60);
}
public int getPacketCountOlderThan(String component, Class packetClass, int minutes) {
String classname = packetClass.getName();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(COUNT_PACKAGES_ODLER);
pstmt.setString(1, "%" + classname + "");
pstmt.setString(2, component);
pstmt.setLong(3, System.currentTimeMillis() - minutes * 60 * 1000);
rs = pstmt.executeQuery();
rs.next();
return rs.getInt(1);
} catch (SQLException sqle) {
Log.error(sqle);
} finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return 0;
}
}
package org.jivesoftware.openfire.plugin.database;
/**
*
* This class represents a log entry for the gojara plugin
*
*
* @author holger.bergunde
*
*/
public class LogEntry {
private String _from;
private String _to;
private String _type;
private long _date;
public LogEntry(String from, String to, String type, long date) {
_from = from;
_to = to;
_type = type;
_date = date;
}
public String getFrom() {
return _from;
}
public String getTo() {
return _to;
}
public String getType() {
return _type;
}
/**
* Date of logentry
*
* @return date in unixtimestamp milliseconds
*/
public long getDate() {
return _date;
}
}
package org.jivesoftware.openfire.plugin.interceptor;
import java.util.HashSet;
import java.util.Set;
import org.apache.log4j.Logger;
import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
public abstract class AbstractInterceptorHandler {
private static Logger Log = Logger.getLogger(AbstractInterceptorHandler.class);
private String _subdomain;
private boolean _isRunning = false;
private Set<PacketInterceptor> _interceptors = new HashSet<PacketInterceptor>();
private InterceptorManager _iManager;
public AbstractInterceptorHandler(String subdomain) {
_subdomain = subdomain;
_iManager = InterceptorManager.getInstance();
}
protected boolean addInterceptor(PacketInterceptor interceptor)
{
if (_isRunning) {
return false;
}
return _interceptors.add(interceptor);
}
protected boolean removeInterceptor(PacketInterceptor interceptor)
{
if (_isRunning) {
return false;
}
return _interceptors.remove(interceptor);
}
public void start()
{
Log.debug("Start handling message interceptors for gateway " + _subdomain);
_isRunning = true;
for (PacketInterceptor interceptor : _interceptors) {
_iManager.addInterceptor(interceptor);
}
}
public void stop()
{
Log.debug("Stop handling message interceptors for gateway " + _subdomain);
if (!_isRunning)
return;
_isRunning = false;
for (PacketInterceptor interceptor : _interceptors) {
_iManager.removeInterceptor(interceptor);
}
}
}
package org.jivesoftware.openfire.plugin.interceptor;
import java.util.List;
import org.dom4j.Element;
import org.dom4j.Node;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.PermissionManager;
import org.jivesoftware.openfire.plugin.Utils;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
public class DiscoPackageInterceptorHandler implements PacketInterceptor {
private PermissionManager _permissions;
private String _subDomain;
private String _host;
public DiscoPackageInterceptorHandler(String subdomain) {
_permissions = new PermissionManager();
_subDomain = subdomain;
XMPPServer server = XMPPServer.getInstance();
_host = server.getServerInfo().getHostname();
}
@Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException
{
if (_permissions.isGatewayLimited(_subDomain)) {
if (packet instanceof IQ) {
IQ iqpacket = (IQ) packet;
Element root = iqpacket.getChildElement();
String ns = root.getNamespaceURI();
if (ns.equals("http://jabber.org/protocol/disco#items") && iqpacket.getType().equals(IQ.Type.result)) {
if (!_permissions.allowedForUser(_subDomain, iqpacket.getTo())) {
if (iqpacket.getFrom().toString().equals(_host)) {
List<Node> nodes = Utils.findNodesInDocument(root.getDocument(), "//discoitems:item");
for (Node node : nodes) {
if (node.valueOf("@jid").equals(_subDomain)) {
root.remove(node);
}
}
}
}
}
}
}
}
}
package org.jivesoftware.openfire.plugin.interceptor;
public class GatewayInterceptorHandler extends AbstractInterceptorHandler {
public GatewayInterceptorHandler(String subdomain) {
super(subdomain);
DiscoPackageInterceptorHandler discoInterceptor = new DiscoPackageInterceptorHandler(subdomain);
RemotePackageInterceptor remoteRosterInterceptor = new RemotePackageInterceptor(subdomain);
StatisticPackageInterceptor statisticInterceptor = new StatisticPackageInterceptor(subdomain);
addInterceptor(remoteRosterInterceptor);
addInterceptor(discoInterceptor);
addInterceptor(statisticInterceptor);
}
}
package org.jivesoftware.openfire.plugin.interceptor;
import java.util.HashMap;
import java.util.Map;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.Utils;
import org.jivesoftware.openfire.plugin.packageProcessor.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.plugin.packageProcessor.CleanUpRosterProcessor;
import org.jivesoftware.openfire.plugin.packageProcessor.ClientToComponentUpdateProcessor;
import org.jivesoftware.openfire.plugin.packageProcessor.DiscoIQResigteredProcessor;
import org.jivesoftware.openfire.plugin.packageProcessor.ReceiveComponentUpdatesProcessor;
import org.jivesoftware.openfire.plugin.packageProcessor.SendRosterProcessor;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
public class RemotePackageInterceptor implements PacketInterceptor {
private static final Logger Log = LoggerFactory.getLogger(RemotePackageInterceptor.class);
private String _mySubdomain;
private Map<String, AbstractRemoteRosterProcessor> _packetProcessor = new HashMap<String, AbstractRemoteRosterProcessor>();
public RemotePackageInterceptor(String initialSubdomain) {
Log.debug("Starting Package Interceptor for "+initialSubdomain);
_mySubdomain = initialSubdomain;
XMPPServer server = XMPPServer.getInstance();
RosterManager rosterMananger = server.getRosterManager();
AbstractRemoteRosterProcessor sendroster = new SendRosterProcessor(rosterMananger, _mySubdomain);
AbstractRemoteRosterProcessor receiveChanges = new ReceiveComponentUpdatesProcessor(rosterMananger, _mySubdomain);
AbstractRemoteRosterProcessor iqRegistered = new DiscoIQResigteredProcessor(_mySubdomain);
AbstractRemoteRosterProcessor cleanUp = new CleanUpRosterProcessor(rosterMananger, _mySubdomain);
AbstractRemoteRosterProcessor updateToComponent = new ClientToComponentUpdateProcessor(_mySubdomain);
_packetProcessor.put("sendRoster", sendroster);
_packetProcessor.put("receiveChanges", receiveChanges);
_packetProcessor.put("sparkIQRegistered", iqRegistered);
_packetProcessor.put("handleCleanUp", cleanUp);
_packetProcessor.put("clientToComponentUpdate", updateToComponent);
}
@Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException
{
if (!processed && incoming) {
if (packet instanceof IQ) {
Log.debug("Incomping unprocessed package i might be interested in. Package: \n"+packet.toString()+"\n");
IQ myPacket = (IQ) packet;
if (myPacket.getFrom() == null || myPacket.getTo() == null) {
/*
* If getTo() == null this is maybe a roster update from the
* Client to the Server, check if we should mirror this
* package to external component
*/
if (myPacket.getFrom() != null && myPacket.getType().equals(IQ.Type.set)
&& myPacket.getTo() == null) {
if (Utils.findNodesInDocument(myPacket.getChildElement().getDocument(), "//roster:item").size() > 0) {
_packetProcessor.get("clientToComponentUpdate").process(myPacket);
}
}
return;
}
@SuppressWarnings("unused")
String to = myPacket.getTo().toString();
String from = myPacket.getFrom().toString();
if (myPacket.getType().equals(IQ.Type.get) && from.equals(_mySubdomain)) {
if (Utils.findNodesInDocument(myPacket.getElement().getDocument(), "//roster:*").size() == 1) {
// This Package is a roster request by remote component
_packetProcessor.get("sendRoster").process(packet);
}
} else if (myPacket.getType().equals(IQ.Type.set) && from.equals(_mySubdomain)) {
if (Utils.findNodesInDocument(myPacket.getElement().getDocument(), "//roster:item").size() >= 1) {
// Component sends roster update
_packetProcessor.get("receiveChanges").process(packet);
}
} else if (myPacket.getType().equals(IQ.Type.get)
&& myPacket.toString().contains("http://jabber.org/protocol/disco#info")
&& myPacket.getTo().toString().equals(_mySubdomain)) {
/*
* modify the disco#info for spark clients if enabled in
* admin panel
*/
_packetProcessor.get("sparkIQRegistered").process(packet);
}
}
// else if (packet instanceof Presence) {
// if (packet.getFrom().toString().equals(_mySubdomain)
// &&
// !JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent",
// false)) {
// System.out.println("MACH EIN CLEANUP!!!!!!");
// _packetProcessor.get("handleCleanUp").process(packet);
// }
// }
}
}
}
package org.jivesoftware.openfire.plugin.interceptor;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.database.DatabaseManager;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
public class StatisticPackageInterceptor implements PacketInterceptor {
private String _subdomain;
private DatabaseManager _db;
public StatisticPackageInterceptor(String subdomain) {
_subdomain = subdomain;
_db = DatabaseManager.getInstance();
}
@Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException {
JID from = packet.getFrom();
JID to = packet.getTo();
if (from != null && to != null && processed && incoming) {
if (from.toString().contains(_subdomain) || to.toString().contains(_subdomain)) {
/*
* Spectrum sends a Ping to itself through the server to check
* if the server is alive. We ignore that for statistics
*/
if (to.toString().equals(from.toString()) && to.toString().equals(_subdomain))
return;
String type = packet.getClass().getName();
_db.addNewLogEntry(_subdomain, type, from.toString(), to.toString());
}
}
}
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Node;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.Packet;
abstract public class AbstractRemoteRosterProcessor {
protected static final Logger Log = LoggerFactory.getLogger(AbstractRemoteRosterProcessor.class);
XMPPServer _server;
PacketRouter _router;
public AbstractRemoteRosterProcessor() {
_server = XMPPServer.getInstance();
}
abstract public void process(Packet packet) throws PacketRejectedException;
protected void dispatchPacket(Packet packet)
{
Log.debug("Sending package to PacketRouter: \n"+packet.toString()+"\n");
PacketRouter router = _server.getPacketRouter();
router.route(packet);
}
protected List<Node> findNodesInDocument(Document doc, String xpath)
{
return Utils.findNodesInDocument(doc, xpath);
}
protected String getUsernameFromJid(String jid)
{
return Utils.getUsernameFromJid(jid);
}
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import java.util.Collection;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
public class CleanUpRosterProcessor extends AbstractRemoteRosterProcessor {
private RosterManager _rosterManager;
private String _subDomain;
public CleanUpRosterProcessor(RosterManager rostermananger, String subdomain) {
Log.debug("Createt CleanUpRosterProcessor for "+subdomain);
_rosterManager = rostermananger;
_subDomain = subdomain;
}
@Override
public void process(Packet packet) throws PacketRejectedException
{
Log.debug("Processing packet in CleanUpRosterProcessor for "+_subDomain);
Presence myPacket = (Presence) packet;
String to = myPacket.getTo().toString();
String username = getUsernameFromJid(to);
if (myPacket.getType() != null && myPacket.getType().equals(Presence.Type.unavailable)) {
try {
Roster roster = _rosterManager.getRoster(username);
Collection<RosterItem> items = roster.getRosterItems();
for (RosterItem item : items) {
String itemName = item.getJid().toString();
if (itemName.contains(_subDomain) && !itemName.equals(_subDomain)) {
Log.debug("Removing contact "+item.getJid().toString()+" from contact list.");
roster.deleteRosterItem(item.getJid(), false);
}
}
} catch (Exception e) {
Log.debug("Execption occured when cleaning up the Roster.",e);
e.printStackTrace();
}
}
}
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import org.dom4j.Element;
import org.dom4j.Node;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
public class ClientToComponentUpdateProcessor extends AbstractRemoteRosterProcessor {
private String _myDomain;
public ClientToComponentUpdateProcessor(String mySubdomain) {
Log.debug("Createt ClientToComponentUpdateProcessor for "+mySubdomain);
_myDomain = mySubdomain;
}
@Override
public void process(Packet packet) throws PacketRejectedException
{
Log.debug("Processing packet in ClientToComponentUpdateProcessor for "+_myDomain);
Element query = ((IQ) packet).getChildElement();
if (query != null && query.getNamespaceURI().equals("jabber:iq:roster")) {
if (findNodesInDocument(query.getDocument(), "//roster:item").size() > 0) {
for (Node n : findNodesInDocument(query.getDocument(), "//roster:item")) {
String jid = n.valueOf("@jid");
// TODO: We ignore remove iq packets for now. There might be
// conflicts
// when we remove our legacy network registration.
if (jid.contains("@" + _myDomain) && !n.valueOf("@subscription").equals("remove")) {
Log.debug("Mirroring packet from local network to legacy component "+_myDomain);
IQ forward = (IQ) packet.createCopy();
forward.setTo(_myDomain);
dispatchPacket(forward);
}
}
}
}
}
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import java.util.Timer;
import java.util.TimerTask;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.dom4j.tree.DefaultAttribute;
import org.dom4j.tree.DefaultElement;
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.util.JiveGlobals;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
public class DiscoIQResigteredProcessor extends AbstractRemoteRosterProcessor {
private boolean _isRegistered = false;
private String _mySubdoman;
public DiscoIQResigteredProcessor(String subdomain) {
Log.debug("Createt DiscoIQResigteredProcessor for " + subdomain);
_mySubdoman = subdomain;
}
@Override
public void process(Packet packet) throws PacketRejectedException
{
Log.debug("Processing packet in DiscoIQResigteredProcessor for "+_mySubdoman);
// Check if the jabber:iq:register is enabled in admin panel
boolean isFeatureEnabled = JiveGlobals.getBooleanProperty("plugin.remoteroster.sparkDiscoInfo", false);
if (!isFeatureEnabled) {
Log.debug("Spark extension is deactivated. Won't change the disco#info");
return;
}
String from = packet.getFrom().toString();
String to = packet.getTo().toString();
final InterceptorManager interceptorManager = InterceptorManager.getInstance();
final PacketInterceptor interceptor = new PacketInterceptor() {
@Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException
{
if (!processed && incoming) {
if (packet instanceof IQ) {
IQ iqPacket = (IQ) packet;
Element packetElement = iqPacket.getChildElement();
if (packetElement == null)
return;
String ns = iqPacket.getChildElement().getNamespace().getURI();
if (iqPacket.getType().equals(IQ.Type.result) && ns.equals("jabber:iq:register")
&& iqPacket.getFrom().toString().equals(_mySubdoman)) {
// Check if we are already registered
setRegistered(iqPacket.toString().contains("<registered/>"));
throw new PacketRejectedException();
} else if (iqPacket.getType().equals(IQ.Type.result)
&& ns.equals("http://jabber.org/protocol/disco#info")
&& iqPacket.getFrom().toString().equals(_mySubdoman)) {
/*
* This is the answer of the disco#info from spark
* to our component. add the jabber:iq:register
* feature if we are registered
*/
if (isRegistered()) {
Log.debug("Modifying disco#info packge to send registered iq feature to Spark user "+iqPacket.getTo().toString());
Attribute attribut = new DefaultAttribute("var", "jabber:iq:registered");
iqPacket.getChildElement().addElement("feature").add(attribut);
}
}
}
}
}
};
Log.debug("Creating my own listener for jabber:iq:register result to external component "+_mySubdoman);
interceptorManager.addInterceptor(interceptor);
IQ askComponent = new IQ();
askComponent.setTo(to);
askComponent.setFrom(from);
askComponent.setType(IQ.Type.get);
Element query = new DefaultElement("query");
query.addNamespace("", "jabber:iq:register");
askComponent.setChildElement(query);
// Remove the package intercepter in 1sec
TimerTask removeInterceptorTask = new TimerTask() {
@Override
public void run()
{
Log.debug("Removing my created listener for jabber:iq:register. Component "+_mySubdoman);
interceptorManager.removeInterceptor(interceptor);
}
};
Timer timer = new Timer();
timer.schedule(removeInterceptorTask, 1000);
// Send the register query to component
dispatchPacket(askComponent);
}
private boolean isRegistered()
{
return _isRegistered;
}
private void setRegistered(boolean bool)
{
_isRegistered = bool;
}
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Node;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
public class ReceiveComponentUpdatesProcessor extends AbstractRemoteRosterProcessor{
private RosterManager _rosterManager;
private String _mySubdomain;
public ReceiveComponentUpdatesProcessor(RosterManager rosterManager, String subdomain) {
_mySubdomain = subdomain;
Log.debug("Createt ReceiveComponentUpdatesProcessor for "+_mySubdomain);
_rosterManager = rosterManager;
}
@Override
public void process(Packet packet) throws PacketRejectedException
{
Log.debug("Processing packet in ClientToComponentUpdateProcessor for "+_mySubdomain);
IQ myPacket = (IQ) packet;
String to = myPacket.getTo().toString();
String username = getUsernameFromJid(to);
List<Node> nodes = findNodesInDocument(myPacket.getElement().getDocument(), "//roster:item");
for (Node n : nodes) {
Roster roster;
try {
roster = _rosterManager.getRoster(username);
String jid = n.valueOf("@jid");
String name = n.valueOf("@name");
if (jid.equals(myPacket.getFrom().toString()))
{
//Do not add the component itself to the contact list
break;
}
List<String> grouplist = new ArrayList<String>();
List<Node> groupnodes = findNodesInDocument(n.getDocument(), "//roster:group");
for (Node ne : groupnodes) {
String groupName = ne.getText();
grouplist.add(groupName);
}
boolean rosterPersisten = JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", true);
Log.debug("Adding user "+jid+" to roster "+ to);
RosterItem item = roster.createRosterItem(new JID(jid), name, grouplist, false, rosterPersisten);
item.setSubStatus(RosterItem.SUB_BOTH);
roster.updateRosterItem(item);
} catch (Exception e) {
Log.debug("Could not add user to Roster "+username,e);
e.printStackTrace();
}
}
}
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import java.util.Collection;
import org.dom4j.Element;
import org.dom4j.tree.DefaultAttribute;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
public class SendRosterProcessor extends AbstractRemoteRosterProcessor {
private RosterManager _rosterManager;
private String _componentName;
public SendRosterProcessor(RosterManager rosterMananger, String componentName) {
Log.debug("Createt SendRosterProcessor for "+componentName);
_rosterManager = rosterMananger;
_componentName = componentName;
}
@Override
public void process(Packet packet) throws PacketRejectedException
{
Log.debug("Processing packet in SendRosterProcessor for "+_componentName);
IQ myPacket = (IQ) packet;
String from = myPacket.getFrom().toString();
String username = getUsernameFromJid(from);
Roster roster;
try {
roster = _rosterManager.getRoster(username);
Collection<RosterItem> items = roster.getRosterItems();
sendRosterToComponent(packet, items);
} catch (UserNotFoundException e) {
e.printStackTrace();
}
}
private void sendRosterToComponent(Packet requestPacket, Collection<RosterItem> items)
{
Log.debug("Sending contacts from user "+requestPacket.getFrom().toString()+" to external Component");
IQ iq = (IQ) requestPacket;
IQ response = IQ.createResultIQ(iq);
response.setTo(_componentName);
Element query = new DefaultElement("query");
for (RosterItem i : items) {
if (i.getJid().toString().contains(_componentName)) {
Log.debug("Roster exchange for external component "+_componentName+". Sending user "+i.getJid().toString());
Element item = new DefaultElement("item");
item.add(new DefaultAttribute("jid", i.getJid().toString()));
item.add(new DefaultAttribute("name", i.getNickname()));
item.add(new DefaultAttribute("subscription", "both"));
for (String s : i.getGroups()) {
Element group = new DefaultElement("group");
group.setText(s);
item.add(group);
}
query.add(item);
}
}
query.addNamespace("", "jabber:iq:roster");
response.setChildElement(query);
dispatchPacket(response);
}
}
package org.jivesoftware.openfire.plugin.servlet;
import java.io.IOException;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.group.Group;
import org.jivesoftware.openfire.group.GroupManager;
public class SearchGroupServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String param = req.getParameter("search");
Element root = new DefaultElement("result");
if (param != null && param.length() > 0) {
GroupManager manager = GroupManager.getInstance();
Collection<Group> groups = manager.getGroups();
for (Group gr : groups) {
if (gr.getName().startsWith(param)) {
root.addElement("item").addText(gr.getName());
}
}
}
resp.getOutputStream().write(root.asXML().getBytes());
resp.getOutputStream().close();
}
}
package org.jivesoftware.openfire.plugin.servlet;
import java.io.IOException;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jivesoftware.openfire.plugin.database.DatabaseManager;
import org.jivesoftware.openfire.plugin.database.LogEntry;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class StatisticsServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = -6872070494892162304L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
DatabaseManager db = DatabaseManager.getInstance();
String component = req.getParameter("component");
String fromString = req.getParameter("date");
/*
* { "packets": [ { "type": "IQ", "from": "holger" }, { "type":
* "Message", "from": "babett", "to": "holger", "date": "1243235344" } ]
* }
*/
int msgCnt = 0;
int iqCnt = 0;
int presenceCnt = 0;
int rosterCnt = 0;
JSONObject root = new JSONObject();
if (component != null && fromString != null) {
JSONArray packetArray = new JSONArray();
try {
root.put("packets", packetArray);
int limit = 40;
long from = Long.valueOf(fromString);
Collection<LogEntry> queryResult = db.getLogsByDateAndLimit(from, limit, component);
for (LogEntry entry : queryResult) {
JSONObject packet = new JSONObject();
packet.put("type", entry.getType()).put("to", entry.getTo()).put("from", entry.getFrom())
.put("date", entry.getDate());
packetArray.put(packet);
if (entry.getType().contains("IQ")) {
iqCnt++;
} else if (entry.getType().contains("Message")) {
msgCnt++;
} else if (entry.getType().contains("Roster")) {
rosterCnt++;
} else if (entry.getType().contains("Presence")) {
presenceCnt++;
}
}
JSONObject numbers = new JSONObject();
numbers.put("msg", msgCnt);
numbers.put("iq", iqCnt);
numbers.put("presence", presenceCnt);
numbers.put("roster", rosterCnt);
root.put("numbers", numbers);
} catch (JSONException e1) {
e1.printStackTrace();
}
}
resp.getOutputStream().write(root.toString().getBytes());
resp.getOutputStream().close();
}
}
<?xml version='1.0' encoding='ISO-8859-1'?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Servlets -->
<servlet>
<servlet-name>stats</servlet-name>
<servlet-class>org.jivesoftware.openfire.plugin.servlet.StatisticsServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>searchGroup</servlet-name>
<servlet-class>org.jivesoftware.openfire.plugin.servlet.SearchGroupServlet</servlet-class>
</servlet>
<!-- Servlet mappings -->
<servlet-mapping>
<servlet-name>stats</servlet-name>
<url-pattern>/stats</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>searchGroup</servlet-name>
<url-pattern>/groups</url-pattern>
</servlet-mapping>
</web-app>
@CHARSET "ISO-8859-1";
.header {
width: 100%;
background-color: gray;
color: white;
padding: 3px;
font-weight: bold;
font-size: 14;
}
.graph {
margin-top: 10px;
width: 100%;
height: 300px;
margin-bottom: 25px;
}
.div-main {
background: #F5F5F5 url(../../../images/jive-body-contentbox-bg.gif) repeat-x
scroll center top;
border: 1px solid #DCDCDC;
margin: 5px;
padding: 10px 10px;
float: left;
}
body table {
font-family: arial, helvetica, sans-serif;
font-size: 13;
}
#logTable {
background-color: #B3B3B3;
width: 100%;
border-spacing: 1px;
border: 1px;
border-style: solid;
border-color: #383838;
}
#logTable thead th {
border-bottom: 1px;
border-style: solid;
text-align: center;
width: 25%;
}
#logTable tfoot tr {
font-weight: bold;
text-align: center;
}
\ No newline at end of file
@CHARSET "ISO-8859-1";
.suggest_link {
background-color: #FFFFFF;
padding: 2px 6px 2px 6px;
}
.suggest_link_over {
background-color: #3366CC;
padding: 2px 6px 2px 6px;
}
.grouptable {
border-spacing:0px;
}
#search_suggest {
position: absolute;
background-color: #FFFFFF;
text-align: left;
border: 1px solid #000000;
display: none;
}
.slider {
margin-left: 48px;
padding-top: 0px;
background-color: rgb(230, 230, 230);
border-color: #CCCCCC rgb(204, 204, 204);
color: white;
width: 550px;
border-style: solid;
border-width: 1px;
border-top: none;
display: none;
}
.sildeHeader {
background-color: #D4D2D2;
color: #000000;
padding-left: 5px;
padding-top: 2px;
padding-bottom: 2px;
border-bottom-color: gray;
border-bottom-width: 1px;
border-bottom-style: solid;
font-weight: bold;
}
.logtable {
border-left:6px;
width: 550px;
height: 100%;
border-spacing: 0px;
}
#loghead{
background-color:#DEDCDC;
font-weight: bold;
color:#404040;
}
#logodd {
background-color:#F0F0F0;
}
#logeven {
background-color:#E9E9E9;
}
#logfoot {
background-color:#DEDCDC;
}
div.graph {
width: 250px;
height: 150px;
float: right;
}
.gatewayHeader {
width: 600px;
background-color: #EEEEEE;
border-color: #CCCCCC rgb(204, 204, 204);
border-style: solid solid solid;
border-width: 1px 1px 1px;
}
.gatewayName {
padding-left: 10px;
}
.gatewayIcon {
border-left: 1px;
}
.gatewayCheckbox {
width: 20px;
}
.configTable {
width: 100%;
border-spacing:0px;
}
.configTable1Column {
width: 50%;
}
.gatewayIcons img {
float: right;
padding: 4px;
}
#permissions {
margin-left: 1%;
padding-top: 0px;
background-color: rgb(230, 230, 230);
border-color: #CCCCCC rgb(204, 204, 204);
color: white;
width: 58%;
border-style: solid;
border-width: 1px;
border-top: none;
display: none;
}
.permissionTableColumn {
width: 50%;
}
.ajaxloading {
padding-left: 4px;
padding-top: 3px;
}
.permissionTitle {
color: black;
size: +2;
}
dt {
width: 50px;
}
.hbg-bar {
padding-left: 5px;
background-color: #369;
color: #fff;
font-weight: bold;
}
.hbg-title {
text-align: center;
font-weight: bold;
}
\ No newline at end of file
This diff is collapsed.
var http = function() {
this.callback = function(a) {};
this.obj = window.XMLHttpRequest ? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
this.load = function(url) {
this.obj.open('get', url);
this.obj.callback = this.callback;
this.obj.onreadystatechange = this.handle;
this.obj.send(null);
};
this.handle = function() {
if (this.readyState == 4)
this.callback(this);
};
};
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
/*
* Horizontal Bar Graph for jQuery
* version 0.1a
*
* http://www.dumpsterdoggy.com/plugins/horiz-bar-graph
*
* Copyright (c) 2009 Chris Missal
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*/
(function($) {
$.fn.horizontalBarGraph = function(options) {
var opts = $.extend({}, $.fn.horizontalBarGraph.defaults, options);
this.children("dt,dd").each(function(i) {
var el = $(this);
if(el.is("dt")) {
el.css({display: "block", float: "left", clear: "left"}).addClass("hbg-label"); return;
} else {
(isTitleDD(el) && opts.hasTitles ? createTitle : createBar)(el, opts);
}
setBarHover(el, opts);
});
tryShowTitle(this);
if(opts.animated) {
createShowButton(opts, this).insertBefore(this);
}
if(opts.colors.length) {
setColors(this.children("dd"), opts);
}
if(opts.hoverColors.length) {
setHoverColors(this.children("dd"), opts);
}
scaleGraph(this);
return this;
};
function scaleGraph(graph) {
var maxWidth = 0;
graph.children("dt").each(function() {
maxWidth = Math.max($(this).width(), maxWidth);
}).css({width: maxWidth+"px"});
}
function setBarHover(bar, opts) {
bar.hover(function() {
bar.addClass("hbg-bar-hover");
}, function() {
bar.removeClass("hbg-bar-hover");
});
}
function createShowButton(opts, graph) {
var button = $("<span />").text(opts.button).addClass("hbg-show-button");
button.click(function() {
graph.children("dd").show('slow', function() { button.fadeOut('normal'); });
});
return button;
}
function createBar(e, opts) {
var val = e.text();
e.css({marginLeft: e.prev().is("dt") ? "5px" : "0px", width: Math.floor(val/opts.interval)+"px"});
e.html($("<span/>").html(val).addClass("hbg-value"));
applyOptions(e, opts);
}
function createTitle(e, opts) {
var title = e.text();
e.prev().attr("title", title);
e.remove();
}
function tryShowTitle(graph) {
var title = graph.attr("title");
if(title) {
$("<div/>").text(title).addClass("hbg-title").insertBefore(graph);
graph.css({overflow: "hidden"});
}
}
function setColors(bars, opts) {
var i = 0;
bars.each(function() {
var c = i++ % opts.colors.length;
$(this).css({backgroundColor: opts.colors[c]});
});
}
function setHoverColors(bars, opts) {
var i = 0;
bars.each(function(i) {
var bar = $(this);
var c = bar.css("background-color");
var hc = opts.hoverColors[i++ % opts.hoverColors.length];
bar.hover(function() {
$(this).css({backgroundColor: hc});
}, function() {
$(this).css({backgroundColor: c});
});
});
}
function applyOptions(e, opts) {
e.css({float: "left"}).addClass("hbg-bar");
if(opts.animated) { e.hide(); }
}
function isTitleDD(e) {
return (e.is(":even") && e.prev().is("dd"));
}
$.fn.horizontalBarGraph.defaults = {
interval: 1,
hasTitles: false,
animated: false,
button: 'Show Values',
colors: [],
hoverColors: []
};
})(jQuery);
This diff is collapsed.
$(document).ready(function() {
drawGraph();
window.setInterval("pollStats()", 1000);
})
var dataIq = [];
var dataMsg = [];
var dataPres = [];
var dataRost = [];
var id = 0;
function drawGraph() {
var options = {
lines : {
show : true
},
points : {
show : false
},
yaxis : {
min : 0
},
xaxis : {
show : false
},
grid : {
backgroundColor : {
colors : [ "#fff", "lightgray" ]
}
}
// xaxis: { tickDecimals: 0, tickSize: 1 }
};
var placeholder = $(".graph");
if (dataIq.length > 50) {
dataIq = dataIq.slice(dataIq.length - 50, dataIq.length - 1);
dataMsg = dataMsg.slice(dataMsg.length - 50, dataMsg.length - 1);
dataPres = dataPres.slice(dataPres.length - 50, dataPres.length - 1);
dataRost = dataRost.slice(dataRost.length - 50, dataRost.length - 1);
}
$.plot($(".graph"), [ {
label : "IQ",
data : dataIq
}, {
label : "Messages",
data : dataMsg
}, {
label : "Roster",
data : dataRost
}, {
label : "Presence",
data : dataPres
} ], options);
// $.plot(placeholder, d1, options);
}
function pollStats() {
var myDate = $('#lastPoll').html();
if (myDate.length < 1) {
myDate = $('#logSince').html();
}
var firstDate = $('#timeStamp:first').html();
if (firstDate == null) {
firstDate = $('#logSince').html();
}
updateData(firstDate);
}
function updateData(lastDate) {
var callback = function(data, textStatus, jqXHR) {
var i = 0;
dataIq.push([ id, data.numbers.iq ]);
dataMsg.push([ id, data.numbers.msg ]);
dataPres.push([ id, data.numbers.presence ]);
dataRost.push([ id, data.numbers.roster ]);
id++;
while (data.packets[i] != null) {
var color = "#DEDEDE";
if (i % 2 == 0) {
color = "#EBEBEB";
}
$('.tableBegin:first').after(
'<tr style="background-color:' + color
+ ';"><td id="timeStamp">' + data.packets[i].date
+ '</td><td>' + data.packets[i].type + '</td><td>'
+ data.packets[i].from + '</td><td>'
+ data.packets[i].to + '</td></tr>');
i++;
}
}
drawGraph();
$.ajax({
url : 'stats?component=xmpp.dew08299&date=' + lastDate,
dataType : 'json',
data : '',
success : callback
});
}
This diff is collapsed.
function searchSuggest(object) {
document.getElementById('search_suggest' + object).innerHTML = '';
var str = escape(document.getElementById('groupSearch' + object).value);
$("#ajaxloading" + object).html("<img src=\"images/ajax-loader.gif\">");
var request = new http();
var f = function(obj) {
var ss = document.getElementById('search_suggest' + object);
var resp = obj.responseXML.documentElement.getElementsByTagName('item');
if (resp.length > 0) {
for ( var i = 0; i < resp.length; i++) {
var suggest = '<div onmouseover="javascript:suggestOver(this);" ';
suggest += 'onmouseout="javascript:suggestOut(this);" ';
suggest += 'onclick="javascript:setSearch(this.innerHTML,'
+ object + ');" ';
suggest += 'class="suggest_link">' + resp[i].textContent
+ '</div>';
ss.innerHTML += suggest;
}
$("#search_suggest" + object).show("slow");
} else {
$("#search_suggest" + object).hide("slow");
}
};
request.callback = f;
request.load('groups?search=' + str);
}
// Mouse over function
function suggestOver(div_value) {
div_value.className = 'suggest_link_over';
}
// Mouse out function
function suggestOut(div_value) {
div_value.className = 'suggest_link';
}
// Click function
function setSearch(value, object) {
document.getElementById("groupSearch" + object).value = value;
// document.getElementById('search_suggest').innerHTML = '';
$("#search_suggest" + object).hide("slow");
checkIfExists(value, object);
}
function checkIfExists(value, object) {
var str = value;
var request = new http();
var f = function(obj) {
var ss = document.getElementById('search_suggest' + object);
var resp = obj.responseXML.documentElement.getElementsByTagName('item');
for ( var i = 0; i < resp.length; i++) {
var stri = String(str);
var respStr = String(resp[i].textContent);
if (stri == respStr) {
$("#ajaxloading" + object).html(
"<img src=\"images/correct-16x16.png\">");
break;
}
}
};
request.callback = f;
request.load('groups?search=' + str);
}
$(document).ready(function() {
$(".browser-data").horizontalBarGraph({
interval : 1
});
var i = 0;
while ($('#logiq' + i).html() != null) {
var iqs = $('#logiq'+i).html();
var msg = $('#logmsg'+i).html();
var roster = $('#logroster'+i).html();
var presence = $('#logpresence'+i).html();
var data = [ {
label : "IQ",
data : parseInt(iqs)
}, {
label : "Messages",
data : parseInt(msg)
}, {
label : "Roster",
data : parseInt(roster)
}, {
label : "Presence",
data : parseInt(presence)
} ];
$.plot($("#pie"+i), data,
{
series: {
pie: {
show: true,
radius: 1,
label: {
show: true,
radius: 3/5,
formatter: function(label, series){
return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;background-color:rgba(100,100,100,0.5);">'+label+'<br/>'+Math.round(series.percent)+'%</div>';
},
background: {
opacity: 0.5,
color: 'gray'
}
}
}
},
legend: {
show: false
}
});
++i;
}
})
function slideToggle(value) {
$(value).slideToggle();
}
<%@page import="org.jivesoftware.openfire.plugin.PermissionManager"%>
<%@ page import="org.dom4j.tree.DefaultElement"%>
<%@ page import="org.jivesoftware.openfire.group.GroupManager"%>
<%@ page import="org.jivesoftware.openfire.group.Group"%>
<%@ page import="org.jivesoftware.openfire.session.ComponentSession"%>
<%@ page import="java.util.Collection"%>
<%@ page import="org.jivesoftware.openfire.SessionManager"%>
<%@ page import="org.jivesoftware.util.JiveGlobals"%>
<%@ page import="java.util.HashMap"%>
<%@ page import="java.util.Map"%>
<%@ page import="java.util.List"%>
<%@ page import="org.jivesoftware.openfire.plugin.database.DatabaseManager"%>
<%@ page import="org.jivesoftware.util.ParamUtils"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt"%>
<%
// webManager.init(request, response, session, application, out);
boolean componentSet = request.getParameter("component") != null;
String component = "";
if (componentSet) {
component = request.getParameter("component");
}
%>
<html>
<head>
<title>Live logs <%=componentSet ? "for " + component : ""%></title>
<meta name="decorator" content="none" />
<link href="./css/liveStats.css" rel="stylesheet" type="text/css">
<script src="./js/http.js" type="text/javascript"></script>
<script src="./js/jquery.js" type="text/javascript"></script>
<script src="./js/liveStats.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript" src="./js/jquery.flot.js"></script>
</head>
<body>
<div class="div-main">
<div class="header">
Live statistics for
<%=componentSet ? component : "NOT SET"%></div>
<div class="graph">Here should appear your stats</div>
<table id="logTable">
<thead>
<tr>
<th>Date</th>
<th>Type</th>
<th>From</th>
<th>To</th>
</tr>
</thead>
<tbody class="tableBegin">
</tbody>
<tfoot>
<tr>
<td colspan="4">Live logging since <span id="logSince"><%=System.currentTimeMillis()%></span> Last poll <span
id="lastPoll"></span></td>
</tr>
</tfoot>
</table>
</div>
</body>
</html>
\ No newline at end of file
This diff is collapsed.
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