Commit 8a215713 authored by Leon Roy's avatar Leon Roy Committed by leonroy

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13321 b35dd754-fafc-0310-a699-88a17e54d16e
parent d96e1190
/**
* $Revision: 3034 $
* $Date: 2005-11-04 21:02:33 -0300 (Fri, 04 Nov 2005) $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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() {
@Override
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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.openfire.archive;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.plugin.MonitoringPlugin;
import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.util.ParamUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConversationPDFServlet extends HttpServlet {
private static final Logger Log = LoggerFactory.getLogger(ConversationPDFServlet.class);
@Override
public void init() throws ServletException {
}
@Override
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 content length 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.getMessage(), nfe);
}
}
}
}
/**
* $Revision: $
* $Date: $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.openfire.archive;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.muc.MUCEventDispatcher;
import org.jivesoftware.openfire.muc.MUCEventListener;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.picocontainer.Startable;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import java.util.Date;
/**
* Interceptor of MUC events of the local conferencing service. The interceptor is responsible
* for reacting to users joining and leaving rooms as well as messages being sent to rooms.
*
* @author Gaston Dombiak
*/
public class GroupConversationInterceptor implements MUCEventListener, Startable {
private ConversationManager conversationManager;
public GroupConversationInterceptor(ConversationManager conversationManager) {
this.conversationManager = conversationManager;
}
public void roomCreated(JID roomJID) {
//Do nothing
}
public void roomDestroyed(JID roomJID) {
// Process this event in the senior cluster member or local JVM when not in a cluster
if (ClusterManager.isSeniorClusterMember()) {
conversationManager.roomConversationEnded(roomJID, new Date());
}
else {
ConversationEventsQueue eventsQueue = conversationManager.getConversationEventsQueue();
eventsQueue.addGroupChatEvent(conversationManager.getRoomConversationKey(roomJID),
ConversationEvent.roomDestroyed(roomJID, new Date()));
}
}
public void occupantJoined(JID roomJID, JID user, String nickname) {
// Process this event in the senior cluster member or local JVM when not in a cluster
if (ClusterManager.isSeniorClusterMember()) {
conversationManager.joinedGroupConversation(roomJID, user, nickname, new Date());
}
else {
ConversationEventsQueue eventsQueue = conversationManager.getConversationEventsQueue();
eventsQueue.addGroupChatEvent(conversationManager.getRoomConversationKey(roomJID),
ConversationEvent.occupantJoined(roomJID, user, nickname, new Date()));
}
}
public void occupantLeft(JID roomJID, JID user) {
// Process this event in the senior cluster member or local JVM when not in a cluster
if (ClusterManager.isSeniorClusterMember()) {
conversationManager.leftGroupConversation(roomJID, user, new 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, new Date());
}
}
else {
ConversationEventsQueue eventsQueue = conversationManager.getConversationEventsQueue();
eventsQueue.addGroupChatEvent(conversationManager.getRoomConversationKey(roomJID),
ConversationEvent.occupantLeft(roomJID, user, new Date()));
}
}
public void nicknameChanged(JID roomJID, JID user, String oldNickname, String newNickname) {
// Process this event in the senior cluster member or local JVM when not in a cluster
if (ClusterManager.isSeniorClusterMember()) {
occupantLeft(roomJID, user);
// Sleep 1 millisecond so that there is a delay between logging out and logging in
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// Ignore
}
occupantJoined(roomJID, user, newNickname);
}
else {
ConversationEventsQueue eventsQueue = conversationManager.getConversationEventsQueue();
eventsQueue.addGroupChatEvent(conversationManager.getRoomConversationKey(roomJID),
ConversationEvent.nicknameChanged(roomJID, user, newNickname, new Date()));
}
}
public void messageReceived(JID roomJID, JID user, String nickname, Message message) {
// Process this event in the senior cluster member or local JVM when not in a cluster
if (ClusterManager.isSeniorClusterMember()) {
conversationManager.processRoomMessage(roomJID, user, nickname, message.getBody(), new Date());
}
else {
boolean withBody = conversationManager.isRoomArchivingEnabled() && (
conversationManager.getRoomsArchived().isEmpty() ||
conversationManager.getRoomsArchived().contains(roomJID.getNode()));
ConversationEventsQueue eventsQueue = conversationManager.getConversationEventsQueue();
eventsQueue.addGroupChatEvent(conversationManager.getRoomConversationKey(roomJID),
ConversationEvent.roomMessageReceived(roomJID, user, nickname, withBody ? message.getBody() : null, new Date()));
}
}
public void privateMessageRecieved(JID toJID, JID fromJID, Message message) {
if(message.getBody() != null) {
if (ClusterManager.isSeniorClusterMember()) {
conversationManager.processMessage(fromJID, toJID, message.getBody(), new Date());
}
else {
ConversationEventsQueue eventsQueue = conversationManager.getConversationEventsQueue();
eventsQueue.addChatEvent(conversationManager.getConversationKey(fromJID, toJID),
ConversationEvent.chatMessageReceived(toJID, fromJID,
conversationManager.isMessageArchivingEnabled() ? message.getBody() : null,
new Date()));
}
}
}
public void roomSubjectChanged(JID roomJID, JID user, String newSubject) {
// Do nothing
}
public void start() {
MUCEventDispatcher.addListener(this);
}
public void stop() {
MUCEventDispatcher.removeListener(this);
conversationManager = null;
}
}
/**
* $RCSfile $
* $Revision $
* $Date $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Created by IntelliJ IDEA.
* User: gato
* Date: Oct 9, 2007
* Time: 11:59:42 PM
* To change this template use File | Settings | File Templates.
*/
public class UserParticipations implements Externalizable {
/**
* Flag that indicates if the participations of the user were in a group chat conversation or a one-to-one
* chat.
*/
private boolean roomParticipation;
/**
* Participations of the same user in a groupchat or one-to-one chat. In a group chat conversation
* a user may leave the conversation and return later so for each time the user joined the room a new
* participation is going to be created. Moreover, each time the user changes his nickname in the room
* a new participation is created.
*/
private List<ConversationParticipation> participations;
public UserParticipations() {
}
public UserParticipations(boolean roomParticipation) {
this.roomParticipation = roomParticipation;
if (roomParticipation) {
participations = new ArrayList<ConversationParticipation>();
}
else {
participations = new CopyOnWriteArrayList<ConversationParticipation>();
}
}
public List<ConversationParticipation> getParticipations() {
return participations;
}
public ConversationParticipation getRecentParticipation() {
return participations.get(0);
}
public void addParticipation(ConversationParticipation participation) {
participations.add(0, participation);
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeBoolean(out, roomParticipation);
ExternalizableUtil.getInstance().writeExternalizableCollection(out, participations);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
roomParticipation = ExternalizableUtil.getInstance().readBoolean(in);
if (roomParticipation) {
participations = new ArrayList<ConversationParticipation>();
}
else {
participations = new CopyOnWriteArrayList<ConversationParticipation>();
}
ExternalizableUtil.getInstance().readExternalizableCollection(in, participations, getClass().getClassLoader());
}
}
/**
* $Revision: $
* $Date: $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.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
}
}
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