Commit 15073cb3 authored by Holger Bergunde's avatar Holger Bergunde Committed by holger.bergunde

OF-490 code clean up gojara, minor changes


git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@12951 b35dd754-fafc-0310-a699-88a17e54d16e
parent fafee09a
<!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.gojara.base.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 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 NUMBER(10) NOT NULL AUTO_INCREMENT,
messageDate NUMBER(10) NOT NULL,
messageType VARCHAR2(255) NOT NULL,
fromJID VARCHAR2(255) NOT NULL,
toJID VARCHAR2(255) NOT NULL,
component VARCHAR2(255) NOT NULL,
PRIMARY KEY (logID)
);
INSERT INTO ofVersion (name, version) VALUES ('gojara', 0);
CREATE TABLE ofGojaraStatistics (
logID bigserial NOT NULL,
messageDate bigint NOT NULL,
messageType tinytext 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);
rr.summary.title=GoJara
\ No newline at end of file
package org.jivesoftware.openfire.plugin.gojara.base;
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.gojara.messagefilter.handler.AbstractInterceptorHandler;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.handler.GatewayInterceptorHandler;
import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper;
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;
/**
* @author Holger Bergunde
*
* This class is the basic reprasentation for the GoJara plugin. It is
* the entry point for openfire to start or stop this plugin.
*
* GoJara has been developed to support XEP-xxx Remote Roster
* Management. Further information: <a
* href="http://jkaluza.fedorapeople.org/remote-roster.html">Here</a>
*
* RemoteRoster enables Spectrum IM support for Openfire. Currently only
* 2.3, 2.4 and 2.5 implemented. 2.1 and 2.2 of the protocol standard is
* not supported by Spectrum IM
*/
public class RemoteRosterPlugin implements Plugin {
private static final Logger Log = LoggerFactory.getLogger(RemoteRosterPlugin.class);
private static PluginManager pluginManager;
private final SessionManager _sessionManager = SessionManager.getInstance();
private Map<String, AbstractInterceptorHandler> _interceptors = new HashMap<String, AbstractInterceptorHandler>();
private Set<String> _waitingForIQResponse = new HashSet<String>();
private PropertyEventListener _settingsObserver;
public void initializePlugin(PluginManager manager, File pluginDirectory) {
Log.debug("Starting RemoteRoster Plugin");
pluginManager = manager;
manageExternalComponents();
listenToSettings();
}
/*
* Handles external components that connect to openfire. We check if the
* external component is maybe a gateway and interesting for us
*/
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 = XpathHelper.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);
}
}
});
}
/*
* Registers a listener for JiveGlobals. We might restart our service, if
* there were some changes for our gateways
*/
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 "gojara";
}
public static PluginManager getPluginManager() {
return pluginManager;
}
private void removeInterceptor(String initialSubdomain) {
AbstractInterceptorHandler interceptor = _interceptors.get(initialSubdomain);
if (interceptor != null) {
_interceptors.remove(initialSubdomain);
interceptor.stop();
}
}
/*
* We are handling all our gateways in a Map with subdomain, like
* icq.myserver.com, to ensure that there is only one interceptor for a
* specified gateway
*/
private void createNewPackageIntercetor(String initialSubdomain) {
AbstractInterceptorHandler interceptor = new GatewayInterceptorHandler(initialSubdomain);
_interceptors.put(initialSubdomain, interceptor);
interceptor.start();
}
}
package org.jivesoftware.openfire.plugin.gojara.base;
import java.util.Map;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.util.PropertyEventListener;
/**
* @author Holger Bergunde
*
* This class implements the @see PropertyEventListener It monitors the
* JiveGlobals to check if there are made changes.
*
*/
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.", ""));
}
/**
*
* If there were changes we are interested in, this template method get
* called. The property string is truncated. Method gets triggered, if the
* property contains substring "plugin.remoteroster.jids."
*
* @param prop
* substring of changes property
*/
protected abstract void changedProperty(String prop);
}
package org.jivesoftware.openfire.plugin.gojara.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;
import org.jivesoftware.util.JiveGlobals;
/**
* @author Holger Bergunde This class is used to store logs in the database. A
* log entry is representated by {@link LogEntry}
*/
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 LIMIT 100";
// 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 final int _dbCleanMinutes;
private DatabaseManager() {
/*
* Load time from globals if it is set. It represents the minutes the
* log entries stay in database until they will get deleted
*/
// TODO: Use PropertyEventListener to check if cleaner.minutes have
// changed
_dbCleanMinutes = JiveGlobals.getIntProperty("plugin.remoteroster.log.cleaner.minutes", 60);
startDatabaseCleanLoop();
}
private void startDatabaseCleanLoop() {
/*
* Database Cleaner thread and check for old log entries every 2 minute
*/
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 {@link 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;
}
/*
* Cleans log entries older than 60 minutes if
* plugin.remoteroster.log.cleaner.minutes is not set
*/
private void cleanOldLogEntries() {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(CLEAN_OLD_DATA);
pstmt.setLong(1, System.currentTimeMillis() - _dbCleanMinutes * 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);
}
}
/**
* Adds new log entry for specified component.
*
* @param component
* subdomain of the external component. e.g.
* icq.myjabberserver.com
* @param type
* string representation of the class. normaly it is like
* {@link org.xmpp.packet}
* @param from
* full qualified JID of user or component this packet was from
* @param to
* full qualified JID of user or component this packet was
* adressed to
*/
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);
}
}
/**
* This method return the last 100 log entries. Every entry is one string
* and added to a ArrayList
*
* @return each log as string in a list
* */
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;
}
/**
* Returns the size of the ofGoJaraStatistics table
*
* @return number rows in database as int or -1 if an error occurred
*/
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 -1;
}
/**
* Counts the number of log entries in the databse that are older than
* specified value
*
* @param component
* subdomain of the component the packages were flown by
* @param packetClass
* the class the packet was instance of
* @param minutes
* the log entry should not be older than (timestamp should be
* smaller than currentTime - minutes)
* @return number of rows found in database or -1 if there was an error
*/
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 -1;
}
}
package org.jivesoftware.openfire.plugin.gojara.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;
/**
* Constructs a log entry
*
* @param from
* full qualified JID as String
* @param to
* full qualified JID as String
* @param type
* class name of packet as String
* @param date
* date of the packet in unixtimestamp miliseconds
*/
public LogEntry(String from, String to, String type, long date) {
_from = from;
_to = to;
_type = type;
_date = date;
}
/**
* Returns the sender of this packet represented by this log entry
*
* @return full qualified jid as string
*/
public String getFrom() {
return _from;
}
/**
* Returns the receiver of this packet represented by this log entry
*
* @return full qualified jid as string
*/
public String getTo() {
return _to;
}
/**
* Returns the packet type as class name
*
* @return class name as string
*/
public String getType() {
return _type;
}
/**
* Date of logentry
*
* @return date in unixtimestamp milliseconds
*/
public long getDate() {
return _date;
}
}
package org.jivesoftware.openfire.plugin.gojara.messagefilter.handler;
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;
/**
*
* A gateway interceptor should extend this class. It supports the child class
* handling their interceptors.
*
* @author Holger Bergunde
*
*/
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();
}
/**
* Add a interceptor to the let it handled by the abstract implementation
* The handle must not be started. You have to stop() until you could add
* new interceptors.
*
* @param interceptor
* @return true if it successfully added, otherwise false
*/
protected boolean addInterceptor(PacketInterceptor interceptor) {
if (_isRunning) {
return false;
}
return _interceptors.add(interceptor);
}
/**
* Remove a interceptor from abstract implementation The handle must not be
* started. You have to stop() until you could remove interceptors.
*
* @param interceptor
* @return true if it successfully added, otherwise false
*/
protected boolean removeInterceptor(PacketInterceptor interceptor) {
if (_isRunning) {
return false;
}
return _interceptors.remove(interceptor);
}
/**
* Start handling the added interceptors.
* If it is started you could not remove or add interceptors
*/
public void start() {
Log.debug("Start handling message interceptors for gateway " + _subdomain);
_isRunning = true;
for (PacketInterceptor interceptor : _interceptors) {
_iManager.addInterceptor(interceptor);
}
}
/**
* Stop handling the added interceptors.
*/
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.gojara.messagefilter.handler;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.interceptors.DiscoPackageInterceptorHandler;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.interceptors.StatisticPackageInterceptor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
/**
*
* This is the main handler for our gateways. It initializes all needed
* interceptors with the component subdomain this handler is bind to You have to
* start and stop this handler manually.
*
* @author Holger Bergunde
*
*/
public class GatewayInterceptorHandler extends AbstractInterceptorHandler {
public GatewayInterceptorHandler(String subdomain) {
super(subdomain);
DiscoPackageInterceptorHandler discoInterceptor = new DiscoPackageInterceptorHandler(subdomain);
RemoteRosterInterceptor remoteRosterInterceptor = new RemoteRosterInterceptor(subdomain);
StatisticPackageInterceptor statisticInterceptor = new StatisticPackageInterceptor(subdomain);
addInterceptor(remoteRosterInterceptor);
addInterceptor(discoInterceptor);
addInterceptor(statisticInterceptor);
}
}
package org.jivesoftware.openfire.plugin.gojara.messagefilter.interceptors;
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.gojara.permissions.PermissionManager;
import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
*
* If the access to external components or gateways is limited to a special
* group in GoJara settings we have to filter the disco#infos from the server to
* the client. If the user is not on the list we are hiding the specified info
* and remove the item containing the gateways subdomain
*
* @author Holger Bergunde
*
*/
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 = XpathHelper.findNodesInDocument(root.getDocument(), "//discoitems:item");
for (Node node : nodes) {
if (node.valueOf("@jid").equals(_subDomain)) {
root.remove(node);
}
}
}
}
}
}
}
}
}
package org.jivesoftware.openfire.plugin.gojara.messagefilter.interceptors;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.database.DatabaseManager;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
/**
*
* This class is only for logging messages between the gateway and the
* registered clients. It uses the database to save the packets from the past 60
* (configurable) minutes.
*
* @author Holger Bergunde
*
*/
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.gojara.messagefilter.remoteroster;
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.gojara.messagefilter.remoteroster.processors.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors.CleanUpRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors.ClientToComponentUpdateProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors.DiscoIQResigteredProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors.ReceiveComponentUpdatesProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors.SendRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper;
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;
/**
* This intercepter handles the main functionality described in the XEP-xxx
* Remote Roster Management standard. <a
* href="http://jkaluza.fedorapeople.org/remote-roster.html">XEP-xxx</a>
*
* It must be registered as an PacketInterceptor for each gateway. It will check
* the incoming packages for several preconditions and redirects the packages
* using a command pattern to individual packet handles.
*
* @author Holger Bergunde
*
*/
public class RemoteRosterInterceptor implements PacketInterceptor {
private static final Logger Log = LoggerFactory.getLogger(RemoteRosterInterceptor.class);
private String _mySubdomain;
private Map<String, AbstractRemoteRosterProcessor> _packetProcessor = new HashMap<String, AbstractRemoteRosterProcessor>();
public RemoteRosterInterceptor(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 (XpathHelper.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 (XpathHelper.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 (XpathHelper.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.gojara.messagefilter.remoteroster.processors;
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.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.Packet;
/**
* This packet and sub packet implements the command pattern. Every processor
* that extends this class have to implement the process function. The
* {@link RemoteRosterInterceptor} will register different implementations of
* this processor and redirect packages according to their functionality
*
* @author Holger Bergunde
*
*/
abstract public class AbstractRemoteRosterProcessor {
protected static final Logger Log = LoggerFactory.getLogger(AbstractRemoteRosterProcessor.class);
XMPPServer _server;
PacketRouter _router;
public AbstractRemoteRosterProcessor() {
_server = XMPPServer.getInstance();
}
/**
* Handles the passed packet. Might throw {@link PacketRejectedException} if
* the package should not be processed by openfire
*
* @param packet
* @throws PacketRejectedException
*/
abstract public void process(Packet packet) throws PacketRejectedException;
/**
* Use this method if you want to send your own packets through openfire
*
* @param packet
* packet to send
*/
protected void dispatchPacket(Packet packet) {
Log.debug("Sending package to PacketRouter: \n" + packet.toString() + "\n");
PacketRouter router = _server.getPacketRouter();
router.route(packet);
}
/**
* Redirects this method. Have a closer look to {@link XpathHelper}
* @param doc
* @param xpath
* @return
*/
protected List<Node> findNodesInDocument(Document doc, String xpath) {
return XpathHelper.findNodesInDocument(doc, xpath);
}
/**
* Redirects this method. Have a closer look to {@link XpathHelper}
* @param doc
* @param xpath
* @return
*/
protected String getUsernameFromJid(String jid) {
return XpathHelper.getUsernameFromJid(jid);
}
}
package org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors;
import java.util.Collection;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
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;
/**
* This class is a part of the command pattern used in
* {@link RemoteRosterInterceptor}. If the remote contacts should not be saved
* permanently in the users roster this command will clean up the users roster.
* If the remote contact went offline it will get removed from user's roster.
*
* @author Holger Bergunde
*
*/
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.gojara.messagefilter.remoteroster.processors;
import org.dom4j.Element;
import org.dom4j.Node;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
* This class implements the XEP-xxx Remote Roster Management standard
* "2.4 Client sends user update". Part of command pattern used in
* {@link RemoteRosterInterceptor}
*
* Further information: <a
* href="http://jkaluza.fedorapeople.org/remote-roster.html#sect-id215516"
* >Here</a>
*
* @author Holger Bergunde
*
*/
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.gojara.messagefilter.remoteroster.processors;
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.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
* This implements a special IQ package for Spark client. Spark checks the
* disco#info package send from external component for a <registered> tag.
* Because spectrum does not support this feature we have to modify the disco
* package from spectrum with the registered tag if the user is registered with
* this gateway. Part of command pattern used in {@link RemoteRosterInterceptor}
*
* @author Holger Bergunde
*
*/
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.gojara.messagefilter.remoteroster.processors;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Node;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
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;
/**
*
* This class implements the XEP-xxx Remote Roster Management standard
* "2.5 Component sends roster update". Part of command pattern used in
* {@link RemoteRosterInterceptor}
*
* Further information: <a
* href="http://jkaluza.fedorapeople.org/remote-roster.html#sect-id215516"
* >Here</a>
*
* @author Holger Bergunde
*
*/
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.gojara.messagefilter.remoteroster.processors;
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.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
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;
/**
* This class implements the XEP-xxx Remote Roster Management standard
* "2.3 Server or component requests user's roster". Part of command pattern
* used in {@link RemoteRosterInterceptor}
*
* Further information: <a
* href="http://jkaluza.fedorapeople.org/remote-roster.html#sect-id215516"
* >Here</a>
*
* @author Holger Bergunde
*
*/
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.gojara.permissions;
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;
/**
*
* Gateways can be limited to a special user group. This manager helps you to
* check if the gateways is limited and if a user is in this group
*
* @author Holger Bergunde
*
*/
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;
}
/**
* Returns the name of the group the usage is limited for the given gateway
*
* @param gateway
* the subdomain of the gateway
* @return name of the group, or "" if there is no group
*/
public String getGroupForGateway(String gateway) {
return JiveGlobals.getProperty("plugin.remoteroster.permissiongroup." + gateway, "");
}
/**
* Set the group name for the limitation
*
* @param gateway
* subdomain of the component
* @param group
* groupname that exists in openfire
*/
public void setGroupForGateway(String gateway, String group) {
JiveGlobals.setProperty("plugin.remoteroster.permissiongroup." + gateway, group);
}
/**
* Remove the limitaion from the specified gateway
*
* @param gateway
* subdomain of the component
*/
public void removeGatewayLimitation(String gateway) {
setGroupForGateway(gateway, "");
}
}
package org.jivesoftware.openfire.plugin.gojara.servlets;
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;
/**
* Searching for groups via ajax from javascript. If there are groups matiching
* the search string it will send back to javascript using xml
*
* @author Holger Bergunde
*
*/
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.gojara.servlets;
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.gojara.database.DatabaseManager;
import org.jivesoftware.openfire.plugin.gojara.database.LogEntry;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Servlet for live statistics using ajax. Sending last messages back for
* statistics using json notation.
*
* @author Holger Bergunde
*
*/
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();
}
}
package org.jivesoftware.openfire.plugin.gojara.utils;
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 XpathHelper {
/**
* 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;
}
}
<?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.gojara.servlets.StatisticsServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>searchGroup</servlet-name>
<servlet-class>org.jivesoftware.openfire.plugin.gojara.servlets.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 {
background-color: #FFF;
color: #363636;
padding: 3px;
margin-left: 20px;
font-weight: bold;
font-size: 14;
font-family: arial, helvetica, sans-serif;
}
.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: #E3E3E3;
color: #363636;
width: 100%;
border-spacing: 0px;
border: 1px;
border-style: solid;
border-color: #575757;
border-spacing: 1px;
}
#tableLimit {
background-color: #E3E3E3;
border-width: 1px;
border-color: #363636;
border-style:solid;
width: 30px;
text-align: right;
float:right;
}
#logTable thead th {
border-bottom: 1px;
border-style: solid;
text-align: center;
border-color: #575757;
}
#logTable tfoot tr {
font-weight: bold;
border: 1px;
border-style: solid;
border-color: #575757;
}
\ 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: 300px;
height: 100px;
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.
This diff is collapsed.
var dataIq = [];
var dataMsg = [];
var dataPres = [];
var dataRost = [];
var id = 0;
var lastTimestamp = 0;
var rowCounter = 0;
var limit = 50;
$(document).ready(function() {
drawGraph();
$('#tableLimit').val(limit);
window.setInterval("pollStats()", 1000);
$('#formLimit').submit(function (e) {
e.preventDefault();
console.log(e);
limit = $('#tableLimit').val();
});
})
function drawGraph() {
var options = {
lines : {
show : true
},
points : {
show : false
},
yaxis : {
min : 0
},
xaxis : {
show : false
},
grid : {
backgroundColor : {
colors : [ "#fff", "lightgray" ]
}
}
};
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);
}
function pollStats() {
var firstDate = $('#logSince').html();
if (lastTimestamp > 0) {
firstDate = lastTimestamp;
}
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 (rowCounter % 2 == 0) {
color = "#EBEBEB";
}
if ($('.entry').length == 0) {
$('.tableBegin').html(
'<tr class="entry" style="background-color:' + color
+ ';"><td class="timeStamp">'
+ formatTimestamp(data.packets[i].date)
+ '</td><td>' + data.packets[i].type
+ '</td><td>' + data.packets[i].from
+ '</td><td>' + data.packets[i].to
+ '</td></tr>');
} else {
$('.entry').filter(":first").before(
'<tr class="entry" style="background-color:' + color
+ ';"><td class="timeStamp">'
+ formatTimestamp(data.packets[i].date)
+ '</td><td>' + data.packets[i].type
+ '</td><td>' + data.packets[i].from
+ '</td><td>' + data.packets[i].to
+ '</td></tr>');
}
lastTimestamp = data.packets[i].date > lastTimestamp ? data.packets[i].date
: lastTimestamp;
if (rowCounter > limit) {
console.log("entferne row!?");
$('.entry').filter(":last").remove();
}
console.log(rowCounter);
rowCounter++;
i++;
}
}
drawGraph();
$.ajax({
url : 'stats?component=xmpp.dew08299&date=' + lastDate,
dataType : 'json',
data : '',
success : callback
});
}
function formatTimestamp(timeStamp) {
function fillZero(data) {
return data < 10 ? "0" + data : data;
}
var date = new Date(timeStamp);
var hours = fillZero(date.getHours());
var minutes = fillZero(date.getMinutes());
var seconds = fillZero(date.getSeconds());
var year = fillZero(date.getFullYear());
var month = fillZero(date.getMonth() + 1);
var day = fillZero(date.getDate());
var formattedTime = hours + ':' + minutes + ':' + seconds + " &nbsp; "
+ day + "." + month + "." + year;
return formattedTime;
}
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,
offset : {
left : 10
}
}
},
legend : {
show : true,
},
grid : {
hoverable : true,
clickable : true
}
});
++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="java.util.Date"%>
<%@ 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");
}
Date currentDate = new Date(System.currentTimeMillis());
String now = currentDate.getHours() + ":" + currentDate.getMinutes() + "." + currentDate.getSeconds()
+ " " + currentDate.getDate() + "." + currentDate.getMonth() + "." + currentDate.getYear();
%>
<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="2">Live logging since <%=now%>
</td>
<td colspan="2"><form id="limitForm">
<input type="text" id="tableLimit">
</form></td>
</tr>
</tfoot>
</table>
</div>
<span id="logSince" style="visibility: hidden;"><%=System.currentTimeMillis()%></span>
</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