Commit f8583a62 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Port from 3.5.1.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@10310 b35dd754-fafc-0310-a699-88a17e54d16e
parent 03f3e222
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Monitoring 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>
Monitoring Plugin Changelog
</h1>
<p><b>1.1.0</b> -- July 31, 2008</p>
<ul>
<li>Compatible version with Openfire 3.6.0. </li>
</ul>
<p><b>1.0.0</b> -- April 24, 2008</p>
<ul>
<li>Initial release. </li>
</ul>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<class>org.jivesoftware.openfire.plugin.MonitoringPlugin</class>
<name>Monitoring Service</name>
<description>Monitors conversations and statistics of the server.</description>
<author>Jive Software</author>
<version>1.1.0</version>
<date>7/31/2008</date>
<minServerVersion>3.5.1</minServerVersion>
<databaseKey>monitoring</databaseKey>
<databaseVersion>0</databaseVersion>
<adminconsole>
<tab id="tab-server">
<sidebar id="stats-dashboard" name="${admin.sidebar.statistics.name}" description="${admin.item.stats-dashboard.description}">
<item id="statistics" name="${admin.sidebar.statistics.name}"
url="stats-dashboard.jsp"
description="${admin.sidebar.statistics.description}"/>
<item id="stats-reporter" name="${admin.item.stats-reporter.name}"
url="stats-reporter.jsp"
description="${admin.item.stats-reporter.description}"/>
</sidebar>
<sidebar id="archiving" name="${admin.sidebar.archiving.name}" description="${admin.sidebar.archiving.description}">
<item id="archive-search" name="${admin.item.archive-search.name}"
url="archive-search.jsp"
description="${admin.item.archive-search.description}"/>
<item id="archiving-settings" name="${admin.item.archive-settings.name}"
url="archiving-settings.jsp"
description="${admin.item.archive-settings.description}"/>
<item id="active-conversations" name="${admin.item.active-conversations.name}"
url="conversations.jsp"
description="${admin.item.active-conversations.description}"/>
</sidebar>
</tab>
</adminconsole>
</plugin>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Monitoring 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>
Monitoring Plugin Readme
</h1>
<h2>Overview</h2>
<p>
The monitoring plugin adds support for chat archiving and server statistics to
Openfire. It provides support for generating various reports on the server
statistics, as well as managing, viewing, and reporting on chat logs.
</p>
<h2>Installation</h2>
<p>
Copy monitoring.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 monitoring.jar file over the existing file.
</p>
<h2>Upgrading from Enterprise</h2>
<p>
If you are upgrading from the Enterprise plugin, and wish to keep your old
statistics and logs, you will need to manually run some database scripts to
perform the migration. Note, if you don't care about your previous
statistics and chat logs, you don't have to worry about these steps.
</p>
<p>
First, you will need to shut down your Openfire server and remove the
enterprise plugin. To do this, perform the following steps:
<ol>
<li>Shut down your Openfire server</li>
<li>Remove the <b>enterprise.jar</b> file and the <b>enterprise</b> directory from the plugins directory in your Openfire install root</li>
<li>Install this plugin, <b>monitoring.jar</b> by copying it into the plugins directory.</li>
<li>At this point, you will need to start up Openfire and let it extract and install the <b>monitoring</b> plugin. You can watch for this to occur by looking under the Plugins tab in the Openfire admin console. Once it appears in the list, continue to the next step.</li>
<li>Shut the server back down again.</li>
<li>Go into your plugins/monitoring/database directory. There you will see
some scripts prefixed with <b>import_</b>. Log into your database, switch
to the Openfire's database as you configured during setup (you can find
this information in conf/openfire.xml if you don't remember it), and run
the script that matches the database you are using. Note that the embedded
database is hsqldb and you can use the script in bin/extra from the Openfire
install root (bin/extra/embedded-db-viewer.sh or
bin/extra/embedded-db-viewer.bat, depending on whether you are using Windows)
to access your embedded database.</li>
<li>Once the script has completed, you can start Openfire back up and all of your settings should be the way they were when you were running the Enterprise plugin.</li>
</ol>
</p>
<h2>Configuration</h2>
<p>
Chat archiving is enabled by default. However, only information about
who is communicating and at what time is stored unless chat transcript
archiving is enabled. To enable chat transcript archiving or group chat
archiving, you will need to log into the admin console and go to:<br />
Server --&gt; Archiving --&gt; Archiving Settings
</p>
</body>
</html>
TRUNCATE TABLE ofConversation;
INSERT INTO ofConversation
(conversationID, room, isExternal, startDate, lastActivity, messageCount)
SELECT conversationID, room, isExternal, startDate, lastActivity, messageCount
FROM entConversation;
TRUNCATE TABLE ofConParticipant;
INSERT INTO ofConParticipant
(conversationID, joinedDate, leftDate, bareJID, jidResource, nickname)
SELECT conversationID, joinedDate, leftDate, bareJID, jidResource, nickname
FROM entConParticipant;
TRUNCATE TABLE ofMessageArchive;
INSERT INTO ofMessageArchive
(conversationID, fromJID, toJID, sentDate, body)
SELECT conversationID, fromJID, toJID, sentDate, body
FROM entMessageArchive;
TRUNCATE TABLE ofRRDs;
INSERT INTO ofRRDs
(id, updatedDate, bytes)
SELECT id, updatedDate, bytes
FROM entRRDs;
TRUNCATE TABLE ofConversation;
INSERT INTO ofConversation
(conversationID, room, isExternal, startDate, lastActivity, messageCount)
SELECT conversationID, room, isExternal, startDate, lastActivity, messageCount
FROM entConversation;
TRUNCATE TABLE ofConParticipant;
INSERT INTO ofConParticipant
(conversationID, joinedDate, leftDate, bareJID, jidResource, nickname)
SELECT conversationID, joinedDate, leftDate, bareJID, jidResource, nickname
FROM entConParticipant;
TRUNCATE TABLE ofMessageArchive;
INSERT INTO ofMessageArchive
(conversationID, fromJID, toJID, sentDate, body)
SELECT conversationID, fromJID, toJID, sentDate, body
FROM entMessageArchive;
TRUNCATE TABLE ofRRDs;
INSERT INTO ofRRDs
(id, updatedDate, bytes)
SELECT id, updatedDate, bytes
FROM entRRDs;
TRUNCATE TABLE ofConversation;
INSERT INTO ofConversation
(conversationID, room, isExternal, startDate, lastActivity, messageCount)
SELECT conversationID, room, isExternal, startDate, lastActivity, messageCount
FROM entConversation;
TRUNCATE TABLE ofConParticipant;
INSERT INTO ofConParticipant
(conversationID, joinedDate, leftDate, bareJID, jidResource, nickname)
SELECT conversationID, joinedDate, leftDate, bareJID, jidResource, nickname
FROM entConParticipant;
TRUNCATE TABLE ofMessageArchive;
INSERT INTO ofMessageArchive
(conversationID, fromJID, toJID, sentDate, body)
SELECT conversationID, fromJID, toJID, sentDate, body
FROM entMessageArchive;
TRUNCATE TABLE ofRRDs;
INSERT INTO ofRRDs
(id, updatedDate, bytes)
SELECT id, updatedDate, bytes
FROM entRRDs;
TRUNCATE TABLE ofConversation;
INSERT INTO ofConversation
(conversationID, room, isExternal, startDate, lastActivity, messageCount)
SELECT conversationID, room, isExternal, startDate, lastActivity, messageCount
FROM entConversation;
TRUNCATE TABLE ofConParticipant;
INSERT INTO ofConParticipant
(conversationID, joinedDate, leftDate, bareJID, jidResource, nickname)
SELECT conversationID, joinedDate, leftDate, bareJID, jidResource, nickname
FROM entConParticipant;
TRUNCATE TABLE ofMessageArchive;
INSERT INTO ofMessageArchive
(conversationID, fromJID, toJID, sentDate, body)
SELECT conversationID, fromJID, toJID, sentDate, body
FROM entMessageArchive;
TRUNCATE TABLE ofRRDs;
INSERT INTO ofRRDs
(id, updatedDate, bytes)
SELECT id, updatedDate, bytes
FROM entRRDs;
commit;
TRUNCATE TABLE ofConversation;
INSERT INTO ofConversation
(conversationID, room, isExternal, startDate, lastActivity, messageCount)
SELECT conversationID, room, isExternal, startDate, lastActivity, messageCount
FROM entConversation;
TRUNCATE TABLE ofConParticipant;
INSERT INTO ofConParticipant
(conversationID, joinedDate, leftDate, bareJID, jidResource, nickname)
SELECT conversationID, joinedDate, leftDate, bareJID, jidResource, nickname
FROM entConParticipant;
TRUNCATE TABLE ofMessageArchive;
INSERT INTO ofMessageArchive
(conversationID, fromJID, toJID, sentDate, body)
SELECT conversationID, fromJID, toJID, sentDate, body
FROM entMessageArchive;
TRUNCATE TABLE ofRRDs;
INSERT INTO ofRRDs
(id, updatedDate, bytes)
SELECT id, updatedDate, bytes
FROM entRRDs;
TRUNCATE TABLE ofConversation;
INSERT INTO ofConversation
(conversationID, room, isExternal, startDate, lastActivity, messageCount)
SELECT conversationID, room, isExternal, startDate, lastActivity, messageCount
FROM entConversation;
TRUNCATE TABLE ofConParticipant;
INSERT INTO ofConParticipant
(conversationID, joinedDate, leftDate, bareJID, jidResource, nickname)
SELECT conversationID, joinedDate, leftDate, bareJID, jidResource, nickname
FROM entConParticipant;
TRUNCATE TABLE ofMessageArchive;
INSERT INTO ofMessageArchive
(conversationID, fromJID, toJID, sentDate, body)
SELECT conversationID, fromJID, toJID, sentDate, body
FROM entMessageArchive;
TRUNCATE TABLE ofRRDs;
INSERT INTO ofRRDs
(id, updatedDate, bytes)
SELECT id, updatedDate, bytes
FROM entRRDs;
-- $Revision$
-- $Date$
INSERT INTO ofVersion (name, version) VALUES ('monitoring', 0);
CREATE TABLE ofConversation (
conversationID INTEGER NOT NULL,
room VARCHAR(512),
isExternal INTEGER NOT NULL,
startDate BIGINT NOT NULL,
lastActivity BIGINT NOT NULL,
messageCount INTEGER NOT NULL,
CONSTRAINT ofConversation_pk PRIMARY KEY (conversationID)
);
CREATE INDEX ofConversation_ext_idx ON ofConversation (isExternal);
CREATE INDEX ofConversation_start_idx ON ofConversation (startDate);
CREATE INDEX ofConversation_last_idx ON ofConversation (lastActivity);
CREATE TABLE ofConParticipant (
conversationID INTEGER NOT NULL,
joinedDate BIGINT NOT NULL,
leftDate BIGINT,
bareJID VARCHAR(255) NOT NULL,
jidResource VARCHAR(255) NOT NULL,
nickname VARCHAR(255)
);
CREATE INDEX entConPar_con_idx ON ofConParticipant (conversationID, bareJID, jidResource, joinedDate);
CREATE INDEX entConPar_jid_idx ON ofConParticipant (bareJID);
CREATE TABLE ofMessageArchive (
conversationID INTEGER NOT NULL,
fromJID VARCHAR(1024) NOT NULL,
toJID VARCHAR(1024) NOT NULL,
sentDate BIGINT NOT NULL,
body LONG VARCHAR
);
CREATE INDEX ofMessageArchive_con_idx ON ofMessageArchive (conversationID);
CREATE TABLE ofRRDs (
id VARCHAR(100) NOT NULL,
updatedDate BIGINT NOT NULL,
bytes BLOB,
CONSTRAINT ofRRDs_pk PRIMARY KEY (id)
);
// $Revision$
// $Date$
INSERT INTO ofVersion (name, version) VALUES ('monitoring', 0);
CREATE TABLE ofConversation (
conversationID BIGINT NOT NULL,
room VARCHAR(1024) NULL,
isExternal INT NOT NULL,
startDate BIGINT NOT NULL,
lastActivity BIGINT NOT NULL,
messageCount INT NOT NULL,
CONSTRAINT ofConversation_pk PRIMARY KEY (conversationID)
);
CREATE INDEX ofConversation_ext_idx ON ofConversation (isExternal);
CREATE INDEX ofConversation_start_idx ON ofConversation (startDate);
CREATE INDEX ofConversation_last_idx ON ofConversation (lastActivity);
CREATE TABLE ofConParticipant (
conversationID BIGINT NOT NULL,
joinedDate BIGINT NOT NULL,
leftDate BIGINT NULL,
bareJID VARCHAR(255) NOT NULL,
jidResource VARCHAR(255) NOT NULL,
nickname VARCHAR(255) NULL
);
CREATE INDEX ofConParticipant_conv_idx ON ofConParticipant (conversationID, bareJID, jidResource, joinedDate);
CREATE INDEX ofConParticipant_jid_idx ON ofConParticipant (bareJID);
CREATE TABLE ofMessageArchive (
conversationID BIGINT NOT NULL,
fromJID VARCHAR(1024) NOT NULL,
toJID VARCHAR(1024) NOT NULL,
sentDate BIGINT NOT NULL,
body LONGVARCHAR
);
CREATE INDEX ofMessageArchive_con_idx ON ofMessageArchive (conversationID);
CREATE TABLE ofRRDs (
id VARCHAR(100) NOT NULL,
updatedDate BIGINT NOT NULL,
bytes VARBINARY NULL,
CONSTRAINT ofRRDs_pk PRIMARY KEY (id)
);
# $Revision$
# $Date$
INSERT INTO ofVersion (name, version) VALUES ('monitoring', 0);
CREATE TABLE ofConversation (
conversationID BIGINT NOT NULL,
room VARCHAR(255) NULL,
isExternal TINYINT NOT NULL,
startDate BIGINT NOT NULL,
lastActivity BIGINT NOT NULL,
messageCount INT NOT NULL,
PRIMARY KEY (conversationID),
INDEX ofConversation_ext_idx (isExternal),
INDEX ofConversation_start_idx (startDate),
INDEX ofConversation_last_idx (lastActivity)
);
CREATE TABLE ofConParticipant (
conversationID BIGINT NOT NULL,
joinedDate BIGINT NOT NULL,
leftDate BIGINT NULL,
bareJID VARCHAR(200) NOT NULL,
jidResource VARCHAR(100) NOT NULL,
nickname VARCHAR(255) NULL,
INDEX ofConParticipant_conv_idx (conversationID, bareJID, jidResource, joinedDate),
INDEX ofConParticipant_jid_idx (bareJID)
);
CREATE TABLE ofMessageArchive (
conversationID BIGINT NOT NULL,
fromJID VARCHAR(255) NOT NULL,
toJID VARCHAR(255) NOT NULL,
sentDate BIGINT NOT NULL,
body TEXT,
INDEX entMsgArchive_con_idx (conversationID)
);
CREATE TABLE ofRRDs (
id VARCHAR(100) NOT NULL,
updatedDate BIGINT NOT NULL,
bytes MEDIUMBLOB NULL,
PRIMARY KEY (id)
);
-- $Revision$
-- $Date$
INSERT INTO ofVersion (name, version) VALUES ('monitoring', 0);
CREATE TABLE ofConversation (
conversationID INTEGER NOT NULL,
room VARCHAR2(1024) NULL,
isExternal NUMBER(2) NOT NULL,
startDate INTEGER NOT NULL,
lastActivity INTEGER NOT NULL,
messageCount INT NOT NULL,
CONSTRAINT ofConversation_pk PRIMARY KEY (conversationID)
);
CREATE INDEX ofConversation_ext_idx ON ofConversation (isExternal);
CREATE INDEX ofConversation_start_idx ON ofConversation (startDate);
CREATE INDEX ofConversation_last_idx ON ofConversation (lastActivity);
CREATE TABLE ofConParticipant (
conversationID INTEGER NOT NULL,
joinedDate INTEGER NOT NULL,
leftDate INTEGER NULL,
bareJID VARCHAR2(255) NOT NULL,
jidResource VARCHAR2(255) NOT NULL,
nickname VARCHAR2(255) NULL
);
CREATE INDEX ofConParticipant_conv_idx ON ofConParticipant (conversationID, bareJID, jidResource, joinedDate);
CREATE INDEX ofConParticipant_jid_idx ON ofConParticipant (bareJID);
CREATE TABLE ofMessageArchive (
conversationID INTEGER NOT NULL,
fromJID VARCHAR2(1024) NOT NULL,
toJID VARCHAR2(1024) NOT NULL,
sentDate INTEGER NOT NULL,
body LONG
);
CREATE INDEX ofMessageArchive_con_idx ON ofMessageArchive (conversationID);
CREATE TABLE ofRRDs (
id VARCHAR2(100) NOT NULL,
updatedDate INTEGER NOT NULL,
bytes BLOB NULL,
CONSTRAINT ofRRDs_pk PRIMARY KEY (id)
);
-- $Revision$
-- $Date$
INSERT INTO ofVersion (name, version) VALUES ('monitoring', 0);
CREATE TABLE ofConversation (
conversationID INTEGER NOT NULL,
room VARCHAR(1024) NULL,
isExternal SMALLINT NOT NULL,
startDate BIGINT NOT NULL,
lastActivity BIGINT NOT NULL,
messageCount INTEGER NOT NULL,
CONSTRAINT ofConversation_pk PRIMARY KEY (conversationID)
);
CREATE INDEX ofConversation_ext_idx ON ofConversation (isExternal);
CREATE INDEX ofConversation_start_idx ON ofConversation (startDate);
CREATE INDEX ofConversation_last_idx ON ofConversation (lastActivity);
CREATE TABLE ofConParticipant (
conversationID INTEGER NOT NULL,
joinedDate BIGINT NOT NULL,
leftDate BIGINT NULL,
bareJID VARCHAR(255) NOT NULL,
jidResource VARCHAR(255) NOT NULL,
nickname VARCHAR(255) NULL
);
CREATE INDEX ofConParticipant_conv_idx ON ofConParticipant (conversationID, bareJID, jidResource, joinedDate);
CREATE INDEX ofConParticipant_jid_idx ON ofConParticipant (bareJID);
CREATE TABLE ofMessageArchive (
conversationID INTEGER NOT NULL,
fromJID VARCHAR(1024) NOT NULL,
toJID VARCHAR(1024) NOT NULL,
sentDate BIGINT NOT NULL,
body TEXT
);
CREATE INDEX ofMessageArchive_con_idx ON ofMessageArchive (conversationID);
CREATE TABLE ofRRDs (
id VARCHAR(100) NOT NULL,
updatedDate BIGINT NOT NULL,
bytes bytea NULL,
CONSTRAINT ofRRDs_pk PRIMARY KEY (id)
);
/* $Revision$ */
/* $Date$ */
INSERT INTO ofVersion (name, version) VALUES ('monitoring', 0);
CREATE TABLE ofConversation (
conversationID BIGINT NOT NULL,
room NVARCHAR(1024) NULL,
isExternal TINYINT NOT NULL,
startDate BIGINT NOT NULL,
lastActivity BIGINT NOT NULL,
messageCount INT NOT NULL,
CONSTRAINT ofConversation_pk PRIMARY KEY (conversationID)
);
CREATE INDEX ofConversation_ext_idx ON ofConversation (isExternal);
CREATE INDEX ofConversation_start_idx ON ofConversation (startDate);
CREATE INDEX ofConversation_last_idx ON ofConversation (lastActivity);
CREATE TABLE ofConParticipant (
conversationID BIGINT NOT NULL,
joinedDate BIGINT NOT NULL,
leftDate BIGINT NULL,
bareJID NVARCHAR(255) NOT NULL,
jidResource NVARCHAR(255) NOT NULL,
nickname NVARCHAR(255) NULL
);
CREATE INDEX ofConParticipant_conv_idx ON ofConParticipant (conversationID, bareJID, jidResource, joinedDate);
CREATE INDEX ofConParticipant_jid_idx ON ofConParticipant (bareJID);
CREATE TABLE ofMessageArchive (
conversationID BIGINT NOT NULL,
fromJID NVARCHAR(1024) NOT NULL,
toJID NVARCHAR(1024) NOT NULL,
sentDate BIGINT NOT NULL,
body NTEXT
);
CREATE INDEX ofMessageArchive_con_idx ON ofMessageArchive (conversationID);
CREATE TABLE ofRRDs (
id NVARCHAR(100) NOT NULL,
updatedDate BIGINT NOT NULL,
bytes IMAGE NULL,
CONSTRAINT ofRRDs_pk PRIMARY KEY (id)
);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/**
* $Revision: 3034 $
* $Date: 2005-11-04 21:02:33 -0300 (Fri, 04 Nov 2005) $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive;
import org.jivesoftware.openfire.cluster.ClusterManager;
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.picocontainer.Startable;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import java.util.Date;
/**
* Intercepts packets to track conversations. Only the following messages
* are processed:
* <ul>
* <li>Messages sent between local users.</li>
* <li>Messages sent between local user and remote entities (e.g. remote users).</li>
* <li>Messages sent between local users and users using legacy networks (i.e. transports).</li>
* </ul>
* Therefore, messages that are sent to Publish-Subscribe or any other internal service are ignored.
*
* @author Matt Tucker
*/
public class ArchiveInterceptor implements PacketInterceptor, Startable {
private ConversationManager conversationManager;
public ArchiveInterceptor(ConversationManager conversationManager) {
this.conversationManager = conversationManager;
}
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException
{
// Ignore any packets that haven't already been processed by interceptors.
if (!processed) {
return;
}
if (packet instanceof Message) {
// Ignore any outgoing messages (we'll catch them when they're incoming).
if (!incoming) {
return;
}
Message message = (Message) packet;
// Ignore any messages that don't have a body so that we skip events.
// Note: XHTML messages should always include a body so we should be ok. It's
// possible that we may need special XHTML filtering in the future, however.
if (message.getBody() != null) {
// Only process messages that are between two users, group chat rooms, or gateways.
if (conversationManager.isConversation(message)) {
// Process this event in the senior cluster member or local JVM when not in a cluster
if (ClusterManager.isSeniorClusterMember()) {
conversationManager.processMessage(message.getFrom(), message.getTo(), message.getBody(), new Date());
}
else {
JID sender = message.getFrom();
JID receiver = message.getTo();
ConversationEventsQueue eventsQueue = conversationManager.getConversationEventsQueue();
eventsQueue.addChatEvent(conversationManager.getConversationKey(sender, receiver),
ConversationEvent.chatMessageReceived(sender, receiver,
conversationManager.isMessageArchivingEnabled() ? message.getBody() : null,
new Date()));
}
}
}
}
}
public void start() {
InterceptorManager.getInstance().addInterceptor(this);
}
public void stop() {
InterceptorManager.getInstance().removeInterceptor(this);
conversationManager = null;
}
}
/**
* $Revision: 3034 $
* $Date: 2005-11-04 21:02:33 -0300 (Fri, 04 Nov 2005) $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive;
import org.xmpp.packet.JID;
import java.util.Date;
/**
* Represents an archived message.
*
* @author Matt Tucker
*/
public class ArchivedMessage {
private long conversationID;
private JID fromJID;
private JID toJID;
private Date sentDate;
private String body;
private boolean roomEvent;
/**
* Creates a new archived message.
*
* @param conversationID the ID of the conversation that the message is associated with.
* @param fromJID the JID of the user that sent the message.
* @param toJID the JID of the user that the message was sent to.
* @param sentDate the date the message was sent.
* @param body the body of the message
* @param roomEvent true if the message belongs to a room event. Eg. User joined room.
*/
public ArchivedMessage(long conversationID, JID fromJID, JID toJID, Date sentDate, String body, boolean roomEvent) {
this.conversationID = conversationID;
// Convert both JID's to bare JID's so that we don't store resource information.
this.fromJID = fromJID;
this.toJID = toJID;
this.sentDate = sentDate;
this.body = body;
this.roomEvent = roomEvent;
}
/**
* The conversation ID that the message is associated with.
*
* @return the conversation ID.
*/
public long getConversationID() {
return conversationID;
}
/**
* The JID of the user that sent the message.
*
* @return the sender JID.
*/
public JID getFromJID() {
return fromJID;
}
/**
* The JID of the user that received the message.
*
* @return the recipient JID.
*/
public JID getToJID() {
return toJID;
}
/**
* The date the message was sent.
*
* @return the date the message was sent.
*/
public Date getSentDate() {
return sentDate;
}
/**
* The body of the message.
*
* @return the body of the message.
*/
public String getBody() {
return body;
}
/**
* Returns true if the message belongs to a room event. Examples of room events are:
* user joined the room or user left the room.
*
* @return true if the message belongs to a room event.
*/
public boolean isRoomEvent() {
return roomEvent;
}
}
\ No newline at end of file
/**
* $Revision: $
* $Date: $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.JID;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Date;
/**
* Conversation events are only used when running in a cluster as a way to send to the senior cluster
* member information about a conversation that is taking place in this cluster node.
*
* @author Gaston Dombiak
*/
public class ConversationEvent implements Externalizable {
private Type type;
private Date date;
private String body;
private JID sender;
private JID receiver;
private JID roomJID;
private JID user;
private String nickname;
/**
* Do not use this constructor. It only exists for serialization purposes.
*/
public ConversationEvent() {
}
public void run(ConversationManager conversationManager) {
if (Type.chatMessageReceived == type) {
conversationManager.processMessage(sender, receiver, body, date);
}
else if (Type.roomDestroyed == type) {
conversationManager.roomConversationEnded(roomJID, date);
}
else if (Type.occupantJoined == type) {
conversationManager.joinedGroupConversation(roomJID, user, nickname, date);
}
else if (Type.occupantLeft == type) {
conversationManager.leftGroupConversation(roomJID, user, date);
// If there are no more occupants then consider the group conversarion over
MUCRoom mucRoom = XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService(roomJID).getChatRoom(roomJID.getNode());
if (mucRoom != null && mucRoom.getOccupantsCount() == 0) {
conversationManager.roomConversationEnded(roomJID, date);
}
}
else if (Type.nicknameChanged == type) {
conversationManager.leftGroupConversation(roomJID, user, date);
conversationManager.joinedGroupConversation(roomJID, user, nickname, new Date(date.getTime() + 1));
}
else if (Type.roomMessageReceived == type) {
conversationManager.processRoomMessage(roomJID, user, nickname, body, date);
}
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeInt(out, type.ordinal());
ExternalizableUtil.getInstance().writeLong(out, date.getTime());
ExternalizableUtil.getInstance().writeBoolean(out, sender != null);
if (sender != null) {
ExternalizableUtil.getInstance().writeSerializable(out, sender);
}
ExternalizableUtil.getInstance().writeBoolean(out, receiver != null);
if (receiver != null) {
ExternalizableUtil.getInstance().writeSerializable(out, receiver);
}
ExternalizableUtil.getInstance().writeBoolean(out, body != null);
if (body != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, body);
}
ExternalizableUtil.getInstance().writeBoolean(out, roomJID != null);
if (roomJID != null) {
ExternalizableUtil.getInstance().writeSerializable(out, roomJID);
}
ExternalizableUtil.getInstance().writeBoolean(out, user != null);
if (user != null) {
ExternalizableUtil.getInstance().writeSerializable(out, user);
}
ExternalizableUtil.getInstance().writeBoolean(out, nickname != null);
if (nickname != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, nickname);
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
type = Type.values()[ExternalizableUtil.getInstance().readInt(in)];
date = new Date(ExternalizableUtil.getInstance().readLong(in));
if (ExternalizableUtil.getInstance().readBoolean(in)) {
sender = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
receiver = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
body = ExternalizableUtil.getInstance().readSafeUTF(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
roomJID = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
user = (JID) ExternalizableUtil.getInstance().readSerializable(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
nickname = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
public static ConversationEvent chatMessageReceived(JID sender, JID receiver, String body, Date date) {
ConversationEvent event = new ConversationEvent();
event.type = Type.chatMessageReceived;
event.sender = sender;
event.receiver = receiver;
event.body = body;
event.date = date;
return event;
}
public static ConversationEvent roomDestroyed(JID roomJID, Date date) {
ConversationEvent event = new ConversationEvent();
event.type = Type.roomDestroyed;
event.roomJID = roomJID;
event.date = date;
return event;
}
public static ConversationEvent occupantJoined(JID roomJID, JID user, String nickname, Date date) {
ConversationEvent event = new ConversationEvent();
event.type = Type.occupantJoined;
event.roomJID = roomJID;
event.user = user;
event.nickname = nickname;
event.date = date;
return event;
}
public static ConversationEvent occupantLeft(JID roomJID, JID user, Date date) {
ConversationEvent event = new ConversationEvent();
event.type = Type.occupantLeft;
event.roomJID = roomJID;
event.user = user;
event.date = date;
return event;
}
public static ConversationEvent nicknameChanged(JID roomJID, JID user, String newNickname, Date date) {
ConversationEvent event = new ConversationEvent();
event.type = Type.nicknameChanged;
event.roomJID = roomJID;
event.user = user;
event.nickname = newNickname;
event.date = date;
return event;
}
public static ConversationEvent roomMessageReceived(JID roomJID, JID user, String nickname, String body,
Date date) {
ConversationEvent event = new ConversationEvent();
event.type = Type.roomMessageReceived;
event.roomJID = roomJID;
event.user = user;
event.nickname = nickname;
event.body = body;
event.date = date;
return event;
}
private static enum Type {
/**
* Event triggered when a room was destroyed.
*/
roomDestroyed,
/**
* Event triggered when a new occupant joins a room.
*/
occupantJoined,
/**
* Event triggered when an occupant left a room.
*/
occupantLeft,
/**
* Event triggered when an occupant changed his nickname in a room.
*/
nicknameChanged,
/**
* Event triggered when a room occupant sent a message to a room.
*/
roomMessageReceived,
/**
* Event triggered when a user sent a message to another user.
*/
chatMessageReceived
}
}
/**
* $Revision: $
* $Date: $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive;
import org.jivesoftware.openfire.archive.cluster.SendConversationEventsTask;
import org.jivesoftware.openfire.reporting.util.TaskEngine;
import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.cache.CacheFactory;
import java.util.*;
/**
* Queue conversation events generated by this JVM and send them to the senior cluster
* member every 3 seconds. This is an optimization to reduce traffic between the cluster
* nodes specialy when under heavy conversations load.
*
* @author Gaston Dombiak
*/
public class ConversationEventsQueue {
private ConversationManager conversationManager;
/**
* Chat events that are pending to be sent to the senior cluster member.
* Key: Conversation Key; Value: List of conversation events.
*/
private final Map<String, List<ConversationEvent>> chatEvents = new HashMap<String, List<ConversationEvent>>();
/**
* Group chat events that are pending to be sent to the senior cluster member.
* Key: Conversation Key; Value: List of conversation events.
*/
private final Map<String, List<ConversationEvent>> roomEvents = new HashMap<String, List<ConversationEvent>>();
public ConversationEventsQueue(ConversationManager conversationManager, TaskEngine taskEngine) {
this.conversationManager = conversationManager;
// Schedule a task to do conversation archiving.
TimerTask sendTask = new TimerTask() {
public void run() {
// Move queued events to a temp place
List<ConversationEvent> eventsToSend = new ArrayList<ConversationEvent>();
synchronized (chatEvents) {
for (List<ConversationEvent> list : chatEvents.values()) {
// Just send the first and last event if we are not archiving messages
if (!ConversationEventsQueue.this.conversationManager.isMessageArchivingEnabled() &&
list.size() > 2) {
eventsToSend.add(list.get(0));
eventsToSend.add(list.get(list.size() - 1));
}
else {
// Send all events
eventsToSend.addAll(list);
}
}
// We can empty the queue now
chatEvents.clear();
}
synchronized (roomEvents) {
for (List<ConversationEvent> list : roomEvents.values()) {
eventsToSend.addAll(list);
}
// We can empty the queue now
roomEvents.clear();
}
// Send the queued events (from the temp place) to the senior cluster member
CacheFactory.doClusterTask(new SendConversationEventsTask(eventsToSend),
ClusterManager.getSeniorClusterMember().toByteArray());
}
};
taskEngine.scheduleAtFixedRate(sendTask, JiveConstants.SECOND * 3, JiveConstants.SECOND * 3);
}
/**
* Queues the one-to-one chat event to be later sent to the senior cluster member.
*
* @param conversationKey unique key that identifies the conversation.
* @param event conversation event.
*/
public void addChatEvent(String conversationKey, ConversationEvent event) {
synchronized (chatEvents) {
List<ConversationEvent> events = chatEvents.get(conversationKey);
if (events == null) {
events = new ArrayList<ConversationEvent>();
chatEvents.put(conversationKey, events);
}
events.add(event);
}
}
/**
* Queues the group chat event to be later sent to the senior cluster member.
*
* @param conversationKey unique key that identifies the conversation.
* @param event conversation event.
*/
public void addGroupChatEvent(String conversationKey, ConversationEvent event) {
synchronized (roomEvents) {
List<ConversationEvent> events = roomEvents.get(conversationKey);
if (events == null) {
events = new ArrayList<ConversationEvent>();
roomEvents.put(conversationKey, events);
}
events.add(event);
}
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive;
import org.jivesoftware.util.StringUtils;
/**
*
*/
public class ConversationInfo {
private long conversationID;
private String participant1;
private String participant2;
/**
* For group converstion we need to send a string array with the occupants' JIDs.
*/
private String[] allParticipants;
private String date;
private String lastActivity;
private String body;
private int messageCount;
private long duration;
public long getConversationID() {
return conversationID;
}
public void setConversationID(long conversationID) {
this.conversationID = conversationID;
}
public String getParticipant1() {
return participant1;
}
public void setParticipant1(String participant1) {
this.participant1 = participant1;
}
public String getParticipant2() {
return participant2;
}
public void setParticipant2(String participant2) {
this.participant2 = participant2;
}
public String[] getAllParticipants() {
return allParticipants;
}
public void setAllParticipants(String[] allParticipants) {
this.allParticipants = allParticipants;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public int getMessageCount() {
return messageCount;
}
public void setMessageCount(int messageCount) {
this.messageCount = messageCount;
}
public String getDuration() {
return StringUtils.getTimeFromLong(duration);
}
public void setDuration(long duration) {
this.duration = duration;
}
public String getLastActivity() {
return lastActivity;
}
public void setLastActivity(String lastActivity) {
this.lastActivity = lastActivity;
}
}
/**
* $Revision$
* $Date$
*
* Copyright (C) 2008 Jive Software. All rights reserved.
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive;
import java.util.Date;
/**
* Listens for conversations being created, finished, and updated. Note that listeners
* are notified using application threads so any long running processing tasks that result
* from notifications should be scheduled for separate threads.
*
* @see ConversationManager#addConversationListener(ConversationListener)
* @author Matt Tucker
*/
public interface ConversationListener {
/**
* A conversation was created.
*
* @param conversation the conversation.
*/
public void conversationCreated(Conversation conversation);
/**
* A conversation was updated, which means that a new message was sent between
* the participants.
*
* @param conversation the conversation.
* @param date the date the conversation was updated.
*/
public void conversationUpdated(Conversation conversation, Date date);
/**
* A conversation ended due to inactivity or because the maximum conversation time
* was hit.
*
* @param conversation the conversation.
*/
public void conversationEnded(Conversation conversation);
}
\ No newline at end of file
/**
* $Revision$
* $Date$
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.plugin.MonitoringPlugin;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.util.ParamUtils;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
*
*/
public class ConversationPDFServlet extends HttpServlet {
public void init() throws ServletException {
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
long conversationID = ParamUtils.getLongParameter(request, "conversationID", -1);
if (conversationID == -1) {
return;
}
MonitoringPlugin plugin = (MonitoringPlugin)XMPPServer.getInstance().getPluginManager().getPlugin(
"monitoring");
ConversationManager conversationManager = (ConversationManager)plugin.getModule(ConversationManager.class);
Conversation conversation;
if (conversationID > -1) {
try {
conversation = new Conversation(conversationManager, conversationID);
ByteArrayOutputStream stream = new ConversationUtils().getConversationPDF(conversation);
// setting some response headers
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
// setting the content type
response.setContentType("application/pdf");
// the contentlength is needed for MSIE!!!
response.setContentLength(stream.size());
// write ByteArrayOutputStream to the ServletOutputStream
ServletOutputStream out = response.getOutputStream();
stream.writeTo(out);
out.flush();
}
catch (NotFoundException nfe) {
Log.error(nfe);
}
}
}
}
/**
* $Revision: $
* $Date: $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Date;
/**
* Participation of a user, connected from a specific resource, in a conversation. If
* a user joins and leaves the conversation many times then we will have many instances
* of this class.
*
* @author Gaston Dombiak
*/
public class ConversationParticipation implements Externalizable {
private Date joined = new Date();
private Date left;
private String nickname;
public ConversationParticipation() {
}
public ConversationParticipation(Date joined) {
this.joined = joined;
}
public ConversationParticipation(Date joined, String nickname) {
this.joined = joined;
this.nickname = nickname;
}
public void participationEnded(Date left) {
this.left = left;
}
/**
* Returns the date when the user joined the conversation.
*
* @return the date when the user joined the conversation.
*/
public Date getJoined() {
return joined;
}
/**
* Returns the date when the user left the conversation.
*
* @return the date when the user left the conversation.
*/
public Date getLeft() {
return left;
}
/**
* Returns the nickname of the user used in the group conversation or
* <tt>null</tt> if participation is in a one-to-one chat.
*
* @return the nickname of the user used in the group conversation.
*/
public String getNickname() {
return nickname;
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeLong(out, joined.getTime());
ExternalizableUtil.getInstance().writeBoolean(out, nickname != null);
if (nickname != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, nickname);
}
ExternalizableUtil.getInstance().writeBoolean(out, left != null);
if (left != null) {
ExternalizableUtil.getInstance().writeLong(out, left.getTime());
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
joined = new Date(ExternalizableUtil.getInstance().readLong(in));
if (ExternalizableUtil.getInstance().readBoolean(in)) {
nickname = ExternalizableUtil.getInstance().readSafeUTF(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
left = new Date(ExternalizableUtil.getInstance().readLong(in));
}
}
}
/**
* $Revision: $
* $Date: $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.archive.cluster;
import org.jivesoftware.openfire.archive.ConversationManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.plugin.MonitoringPlugin;
import org.jivesoftware.util.cache.ClusterTask;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Task that will return the number of current conversations taking place in the senior cluster member.
* All conversations in the cluster are kept in the senior cluster member.
*
* @author Gaston Dombiak
*/
public class GetConversationCountTask implements ClusterTask {
private int conversationCount;
public Object getResult() {
return conversationCount;
}
public void run() {
MonitoringPlugin plugin = (MonitoringPlugin) XMPPServer.getInstance().getPluginManager().getPlugin(
"monitoring");
ConversationManager conversationManager = (ConversationManager)plugin.getModule(ConversationManager.class);
conversationCount = conversationManager.getConversationCount();
}
public void writeExternal(ObjectOutput out) throws IOException {
// Do nothing
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// Do nothing
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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