Commit 52a517c6 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

More clustering work (MUC support).

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@8787 b35dd754-fafc-0310-a699-88a17e54d16e
parent a3ac7356
......@@ -99,7 +99,7 @@ public class XMPPServer {
private Date startDate;
private boolean initialized = false;
private NodeID nodeID;
private static final NodeID DEFAULT_NODE_ID = new NodeID(new byte[0]);
private static final NodeID DEFAULT_NODE_ID = NodeID.getInstance(new byte[0]);
/**
* All modules loaded by this server
......@@ -313,7 +313,7 @@ public class XMPPServer {
name = JiveGlobals.getProperty("xmpp.domain", "127.0.0.1").toLowerCase();
version = new Version(3, 4, 0, Version.ReleaseStatus.Alpha, 1);
version = new Version(3, 4, 0, Version.ReleaseStatus.Alpha, 2);
if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
setupMode = false;
}
......
......@@ -334,6 +334,20 @@ public class ClusterManager {
return CacheFactory.isSeniorClusterMember();
}
/**
* Returns the id of the node that is the senior cluster member. When not in a cluster the returned
* node id will be the {@link XMPPServer#getNodeID()}.
*
* @return the id of the node that is the senior cluster member.
*/
public static NodeID getSeniorClusterMember() {
byte[] clusterMemberID = CacheFactory.getSeniorClusterMemberID();
if (clusterMemberID == null) {
return XMPPServer.getInstance().getNodeID();
}
return NodeID.getInstance(clusterMemberID);
}
private static class Event {
private EventType type;
private byte[] nodeID;
......
......@@ -17,7 +17,9 @@ import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Class which wraps the byte[] we use to identify cluster members. The main reason
......@@ -29,12 +31,38 @@ import java.util.Arrays;
* @author Gaston Dombiak
*/
public class NodeID implements Externalizable {
private static List<NodeID> instances = new ArrayList<NodeID>();
private byte[] nodeID;
public static synchronized NodeID getInstance(byte[] nodeIdBytes) {
for (NodeID nodeID : instances) {
if (nodeID.equals(nodeIdBytes)) {
return nodeID;
}
}
NodeID answer = new NodeID(nodeIdBytes);
instances.add(answer);
return answer;
}
public static synchronized void deleteInstance(byte[] nodeIdBytes) {
NodeID toDelete = null;
for (NodeID nodeID : instances) {
if (nodeID.equals(nodeIdBytes)) {
toDelete = nodeID;
break;
}
}
if (toDelete != null) {
instances.remove(toDelete);
}
}
public NodeID() {
}
public NodeID(byte[] nodeIdBytes) {
private NodeID(byte[] nodeIdBytes) {
this.nodeID = nodeIdBytes;
}
......
......@@ -306,7 +306,7 @@ public class IQDiscoInfoHandler extends IQHandler implements ClusterEventListene
public void leftCluster(byte[] nodeID) {
if (ClusterManager.isSeniorClusterMember()) {
NodeID leftNode = new NodeID(nodeID);
NodeID leftNode = NodeID.getInstance(nodeID);
// Remove server features added by node that is gone
for (Map.Entry<String, Set<NodeID>> entry : serverFeatures.entrySet()) {
String namespace = entry.getKey();
......
......@@ -365,7 +365,7 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
public void leftCluster(byte[] nodeID) {
if (ClusterManager.isSeniorClusterMember()) {
NodeID leftNode = new NodeID(nodeID);
NodeID leftNode = NodeID.getInstance(nodeID);
for (Map.Entry<String, ClusteredServerItem> entry : serverItems.entrySet()) {
String jid = entry.getKey();
Lock lock = LockManager.getLock(jid + "item");
......
......@@ -11,21 +11,16 @@
package org.jivesoftware.openfire.muc;
import org.dom4j.Element;
import org.jivesoftware.openfire.muc.spi.LocalMUCRole;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.Log;
import org.xmpp.packet.Message;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.TimeZone;
import org.jivesoftware.openfire.muc.spi.MUCRoleImpl;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.FastDateFormat;
import org.dom4j.Element;
import org.xmpp.packet.Message;
import java.util.*;
/**
* Represents the amount of history requested by an occupant while joining a room. There are
......@@ -136,7 +131,7 @@ public class HistoryRequest {
* @param joinRole the user that will receive the history.
* @param roomHistory the history of the room.
*/
public void sendHistory(MUCRoleImpl joinRole, MUCRoomHistory roomHistory) {
public void sendHistory(LocalMUCRole joinRole, MUCRoomHistory roomHistory) {
if (!isConfigured()) {
Iterator history = roomHistory.getMessageHistory();
while (history.hasNext()) {
......
......@@ -11,13 +11,13 @@
package org.jivesoftware.openfire.muc;
import org.jivesoftware.openfire.muc.cluster.UpdateHistoryStrategy;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.CacheFactory;
import org.xmpp.packet.Message;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
......@@ -96,10 +96,18 @@ public class HistoryStrategy {
* @param max the maximum number of messages to store in applicable strategies.
*/
public void setMaxNumber(int max) {
if (maxNumber == max) {
// Do nothing since value has not changed
return;
}
this.maxNumber = max;
if (contextPrefix != null){
JiveGlobals.setProperty(contextPrefix + ".maxNumber", Integer.toString(maxNumber));
}
if (parent == null) {
// Update the history strategy of the MUC service
CacheFactory.doClusterTask(new UpdateHistoryStrategy(this));
}
}
/**
......@@ -108,12 +116,20 @@ public class HistoryStrategy {
* @param newType The new type of chat history to use.
*/
public void setType(Type newType){
if (type == newType) {
// Do nothing since value has not changed
return;
}
if (newType != null){
type = newType;
}
if (contextPrefix != null){
JiveGlobals.setProperty(contextPrefix + ".type", type.toString());
}
if (parent == null) {
// Update the history strategy of the MUC service
CacheFactory.doClusterTask(new UpdateHistoryStrategy(this));
}
}
/**
......@@ -195,6 +211,8 @@ public class HistoryStrategy {
*/
public Iterator<Message> getMessageHistory(){
LinkedList<Message> list = new LinkedList<Message>(history);
// Sort messages. Messages may be out of order when running inside of a cluster
Collections.sort(list, new MessageComparator());
return list.iterator();
}
......@@ -207,6 +225,8 @@ public class HistoryStrategy {
*/
public ListIterator<Message> getReverseMessageHistory(){
LinkedList<Message> list = new LinkedList<Message>(history);
// Sort messages. Messages may be out of order when running inside of a cluster
Collections.sort(list, new MessageComparator());
return list.listIterator(list.size());
}
......@@ -227,14 +247,14 @@ public class HistoryStrategy {
*/
public void setTypeFromString(String typeName) {
try {
setType(Type.valueOf(typeName));
type = Type.valueOf(typeName);
}
catch (Exception e) {
if (parent != null) {
setType(Type.defaulType);
type = Type.defaulType;
}
else {
setType(Type.number);
type = Type.number;
}
}
}
......@@ -251,7 +271,7 @@ public class HistoryStrategy {
String maxNumberString = JiveGlobals.getProperty(prefix + ".maxNumber");
if (maxNumberString != null && maxNumberString.trim().length() > 0){
try {
setMaxNumber(Integer.parseInt(maxNumberString));
this.maxNumber = Integer.parseInt(maxNumberString);
}
catch (Exception e){
Log.info("Jive property " + prefix + ".maxNumber not a valid number.");
......@@ -269,4 +289,12 @@ public class HistoryStrategy {
public boolean hasChangedSubject() {
return roomSubject != null;
}
private static class MessageComparator implements Comparator<Message> {
public int compare(Message o1, Message o2) {
String stamp1 = o1.getChildElement("x", "jabber:x:delay").attributeValue("stamp");
String stamp2 = o2.getChildElement("x", "jabber:x:delay").attributeValue("stamp");
return stamp1.compareTo(stamp2);
}
}
}
......@@ -11,7 +11,7 @@
package org.jivesoftware.openfire.muc;
import org.dom4j.Element;
import org.jivesoftware.openfire.cluster.NodeID;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
......@@ -27,6 +27,139 @@ import org.xmpp.packet.Presence;
*/
public interface MUCRole {
/**
* Obtain the current presence status of a user in a chatroom.
*
* @return The presence of the user in the room.
*/
public Presence getPresence();
/**
* Set the current presence status of a user in a chatroom.
*
* @param presence The presence of the user in the room.
*/
public void setPresence(Presence presence);
/**
* Call this method to promote or demote a user's role in a chatroom.
* It is common for the chatroom or other chat room members to change
* the role of users (a moderator promoting another user to moderator
* status for example).<p>
* <p/>
* Owning ChatUsers should have their membership roles updated.
*
* @param newRole The new role that the user will play.
* @throws NotAllowedException Thrown if trying to change the moderator role to an owner or
* administrator.
*/
public void setRole(Role newRole) throws NotAllowedException;
/**
* Obtain the role state of the user.
*
* @return The role status of this user.
*/
public Role getRole();
/**
* Call this method to promote or demote a user's affiliation in a chatroom.
*
* @param newAffiliation the new affiliation that the user will play.
* @throws NotAllowedException thrown if trying to ban an owner or an administrator.
*/
public void setAffiliation(Affiliation newAffiliation) throws NotAllowedException;
/**
* Obtain the affiliation state of the user.
*
* @return The affiliation status of this user.
*/
public Affiliation getAffiliation();
/**
* Changes the nickname of the occupant within the room to the new nickname.
*
* @param nickname the new nickname of the occupant in the room.
*/
void changeNickname(String nickname);
/**
* Obtain the nickname for the user in the chatroom.
*
* @return The user's nickname in the room or null if invisible.
*/
public String getNickname();
/**
* Destroys this role after the occupant left the room. This role will be
* removed from MUCUser.
*/
public void destroy();
/**
* Returns true if the room occupant does not want to get messages broadcasted to all
* room occupants. This type of users are called "deaf" occupants. Deaf occupants will still
* be able to get private messages, presences, IQ packets or room history.<p>
*
* To be a deaf occupant the initial presence sent to the room while joining the room has
* to include the following child element:
* <pre>
* &lt;x xmlns='http://jivesoftware.org/protocol/muc'&gt;
* &lt;deaf-occupant/&gt;
* &lt;/x&gt;
* </pre>
*
* Note that this is a custom extension to the MUC specification.
*
* @return true if the room occupant does not want to get messages broadcasted to all
* room occupants.
*/
boolean isVoiceOnly();
/**
* Obtain the chat room that hosts this user's role.
*
* @return The chatroom hosting this role.
*/
public MUCRoom getChatRoom();
/**
* Obtain the XMPPAddress representing this role in a room: room@server/nickname
*
* @return The Jabber ID that represents this role in the room.
*/
public JID getRoleAddress();
/**
* Obtain the XMPPAddress of the user that joined the room. A <tt>null</tt> null value
* represents the room's role.
*
* @return The address of the user that joined the room or null if this role belongs to the room itself.
*/
public JID getUserAddress();
/**
* Returns true if this room occupant is hosted by this JVM.
*
* @return true if this room occupant is hosted by this JVM
*/
public boolean isLocal();
/**
* Returns the id of the node that is hosting the room occupant.
*
* @return the id of the node that is hosting the room occupant.
*/
public NodeID getNodeID();
/**
* Sends a packet to the user.
*
* @param packet The packet to send
*/
public void send(Packet packet);
public enum Role {
/**
......@@ -141,125 +274,4 @@ public interface MUCRole {
}
}
}
/**
* Obtain the current presence status of a user in a chatroom.
*
* @return The presence of the user in the room.
*/
public Presence getPresence();
/**
* Returns the extended presence information that includes information about roles,
* affiliations, JIDs, etc.
*
* @return the extended presence information that includes information about roles,
* affiliations.
*/
public Element getExtendedPresenceInformation();
/**
* Set the current presence status of a user in a chatroom.
*
* @param presence The presence of the user in the room.
*/
public void setPresence(Presence presence);
/**
* Call this method to promote or demote a user's role in a chatroom.
* It is common for the chatroom or other chat room members to change
* the role of users (a moderator promoting another user to moderator
* status for example).<p>
* <p/>
* Owning ChatUsers should have their membership roles updated.
*
* @param newRole The new role that the user will play.
* @throws NotAllowedException Thrown if trying to change the moderator role to an owner or
* administrator.
*/
public void setRole(Role newRole) throws NotAllowedException;
/**
* Obtain the role state of the user.
*
* @return The role status of this user.
*/
public Role getRole();
/**
* Call this method to promote or demote a user's affiliation in a chatroom.
*
* @param newAffiliation the new affiliation that the user will play.
* @throws NotAllowedException thrown if trying to ban an owner or an administrator.
*/
public void setAffiliation(Affiliation newAffiliation) throws NotAllowedException;
/**
* Obtain the affiliation state of the user.
*
* @return The affiliation status of this user.
*/
public Affiliation getAffiliation();
/**
* Obtain the nickname for the user in the chatroom.
*
* @return The user's nickname in the room or null if invisible.
*/
public String getNickname();
/**
* Changes the nickname of the occupant within the room to the new nickname.
*
* @param nickname the new nickname of the occupant in the room.
*/
public void changeNickname(String nickname);
/**
* Returns true if the room occupant does not want to get messages broadcasted to all
* room occupants. This type of users are called "deaf" occupants. Deaf occupants will still
* be able to get private messages, presences, IQ packets or room history.<p>
*
* To be a deaf occupant the initial presence sent to the room while joining the room has
* to include the following child element:
* <pre>
* &lt;x xmlns='http://jivesoftware.org/protocol/muc'&gt;
* &lt;deaf-occupant/&gt;
* &lt;/x&gt;
* </pre>
*
* Note that this is a custom extension to the MUC specification.
*
* @return true if the room occupant does not want to get messages broadcasted to all
* room occupants.
*/
boolean isVoiceOnly();
/**
* Obtain the chat user that plays this role.
*
* @return The chatuser playing this role.
*/
public MUCUser getChatUser();
/**
* Obtain the chat room that hosts this user's role.
*
* @return The chatroom hosting this role.
*/
public MUCRoom getChatRoom();
/**
* Obtain the XMPPAddress representing this role in a room: room@server/nickname
*
* @return The Jabber ID that represents this role in the room.
*/
public JID getRoleAddress();
/**
* Sends a packet to the user.
*
* @param packet The packet to send
*/
public void send(Packet packet);
}
\ No newline at end of file
......@@ -11,23 +11,26 @@
package org.jivesoftware.openfire.muc;
import java.util.List;
import java.util.Date;
import java.util.Collection;
import org.dom4j.Element;
import org.jivesoftware.database.JiveID;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.muc.spi.IQAdminHandler;
import org.jivesoftware.openfire.muc.spi.IQOwnerHandler;
import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.muc.spi.LocalMUCRole;
import org.jivesoftware.openfire.muc.spi.LocalMUCUser;
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.database.JiveID;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Message;
import org.jivesoftware.util.JiveConstants;
import org.jivesoftware.util.NotFoundException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import java.io.Externalizable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
......@@ -37,7 +40,7 @@ import org.xmpp.packet.Packet;
* @author Gaston Dombiak
*/
@JiveID(JiveConstants.MUC_ROOM)
public interface MUCRoom {
public interface MUCRoom extends Externalizable {
/**
* Get the name of this room.
......@@ -139,13 +142,13 @@ public interface MUCRoom {
List<MUCRole> getOccupantsByBareJID(String jid) throws UserNotFoundException;
/**
* Obtain the role of a given user in the room by his full JID.
* Returns the role of a given user in the room by his full JID or <tt>null</tt>
* if no role was found for the specified user.
*
* @param jid The full jid of the user you'd like to obtain
* @return The user's role in the room
* @throws UserNotFoundException If there is no user with the given nickname
* @return The user's role in the room or null if not found.
*/
MUCRole getOccupantByFullJID(JID jid) throws UserNotFoundException;
MUCRole getOccupantByFullJID(JID jid);
/**
* Obtain the roles of all users in the chatroom.
......@@ -209,7 +212,7 @@ public interface MUCRoom {
* @throws NotAcceptableException If the registered user is trying to join with a
* nickname different than the reserved nickname.
*/
MUCRole joinRoom(String nickname, String password, HistoryRequest historyRequest, MUCUser user,
LocalMUCRole joinRoom(String nickname, String password, HistoryRequest historyRequest, LocalMUCUser user,
Presence presence) throws UnauthorizedException, UserAlreadyExistsException,
RoomLockedException, ForbiddenException, RegistrationRequiredException,
ConflictException, ServiceUnavailableException, NotAcceptableException;
......@@ -217,10 +220,9 @@ public interface MUCRoom {
/**
* Remove a member from the chat room.
*
* @param nickname The user to remove
* @throws UserNotFoundException If the nickname is not found.
* @param leaveRole room occupant that left the room.
*/
void leaveRoom(String nickname) throws UserNotFoundException;
void leaveRoom(MUCRole leaveRole);
/**
* Destroys the room. Each occupant will be removed and will receive a presence stanza of type
......@@ -417,13 +419,23 @@ public interface MUCRoom {
*/
public boolean isManuallyLocked();
/**
* An event callback fired whenever an occupant updated his presence in the chatroom.
*
* @param occupantRole occupant that changed his presence in the room.
* @param newPresence presence sent by the occupant.
*/
public void presenceUpdated(MUCRole occupantRole, Presence newPresence);
/**
* An event callback fired whenever an occupant changes his nickname within the chatroom.
*
* @param occupantRole occupant that changed his nickname in the room.
* @param newPresence presence sent by the occupant with the new nickname.
* @param oldNick old nickname within the room.
* @param newNick new nickname within the room.
*/
public void nicknameChanged(String oldNick, String newNick);
public void nicknameChanged(MUCRole occupantRole, Presence newPresence, String oldNick, String newNick);
/**
* Changes the room's subject if the occupant has enough permissions. The occupant must be
......
......@@ -83,7 +83,7 @@ public final class MUCRoomHistory {
// Set the Full JID as the "from" attribute
try {
MUCRole role = room.getOccupant(message.getFrom().getResource());
delayElement.addAttribute("from", role.getChatUser().getAddress().toString());
delayElement.addAttribute("from", role.getUserAddress().toString());
}
catch (UserNotFoundException e) {
// Ignore.
......@@ -105,8 +105,7 @@ public final class MUCRoomHistory {
// Set the Full JID as the "from" attribute
try {
MUCRole role = room.getOccupant(packet.getFrom().getResource());
delayInformation.addAttribute("from", role.getChatUser().getAddress()
.toString());
delayInformation.addAttribute("from", role.getUserAddress().toString());
}
catch (UserNotFoundException e) {
// Ignore.
......
......@@ -11,12 +11,9 @@
package org.jivesoftware.openfire.muc;
import org.jivesoftware.util.NotFoundException;
import org.jivesoftware.openfire.ChannelHandler;
import org.xmpp.packet.JID;
import java.util.Iterator;
/**
* The chat user is a separate user abstraction for interacting with
* the chat server. Centralizing chat users to the Jabber entity that
......@@ -32,13 +29,6 @@ import java.util.Iterator;
*/
public interface MUCUser extends ChannelHandler {
/**
* Obtain a user ID (useful for database indexing).
*
* @return The user's id number if any (-1 indicates the implementation doesn't support ids)
*/
long getID();
/**
* Obtain the address of the user. The address is used by services like the core
* server packet router to determine if a packet should be sent to the handler.
......@@ -48,51 +38,4 @@ public interface MUCUser extends ChannelHandler {
* @return the address of the packet handler.
*/
public JID getAddress();
/**
* Obtain the role of the user in a particular room.
*
* @param roomName The name of the room we're interested in
* @return The role the user plays in that room
* @throws NotFoundException if the user does not have a role in the given room
*/
MUCRole getRole(String roomName) throws NotFoundException;
/**
* Get all roles for this user.
*
* @return Iterator over all roles for this user
*/
Iterator<MUCRole> getRoles();
/**
* Adds the role of the user in a particular room.
*
* @param roomName The name of the room.
* @param role The new role of the user.
*/
void addRole(String roomName, MUCRole role);
/**
* Removes the role of the user in a particular room.<p>
*
* Note: PREREQUISITE: A lock on this object has already been obtained.
*
* @param roomName The name of the room we're being removed
*/
void removeRole(String roomName);
/**
* Returns true if the user is currently present in one or more rooms.
*
* @return true if the user is currently present in one or more rooms.
*/
boolean isJoined();
/**
* Get time (in milliseconds from System currentTimeMillis()) since last packet.
*
* @return The time when the last packet was sent from this user
*/
long getLastPacketTime();
}
\ No newline at end of file
......@@ -11,7 +11,6 @@
package org.jivesoftware.openfire.muc;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.xmpp.component.Component;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
......@@ -235,30 +234,6 @@ public interface MultiUserChatServer extends Component {
*/
void removeChatRoom(String roomName);
/**
* Removes a user from all chat rooms.
*
* @param jabberID The user's normal jid, not the chat nickname jid.
*/
void removeUser(JID jabberID);
/**
* Obtain a chat user by XMPPAddress.
*
* @param userjid The XMPPAddress of the user.
* @return The chatuser corresponding to that XMPPAddress.
* @throws UserNotFoundException If the user is not found and can't be auto-created.
*/
MUCUser getChatUser(JID userjid) throws UserNotFoundException;
/**
* Broadcast a given message to all members of this chat room. The sender is always set to be
* the chatroom.
*
* @param msg The message to broadcast.
*/
void serverBroadcast(String msg);
/**
* Returns the total chat time of all rooms combined.
*
......
......@@ -36,11 +36,11 @@ import java.util.List;
* @author Gaston Dombiak
*/
public class IQAdminHandler {
private MUCRoomImpl room;
private LocalMUCRoom room;
private PacketRouter router;
public IQAdminHandler(MUCRoomImpl chatroom, PacketRouter packetRouter) {
public IQAdminHandler(LocalMUCRoom chatroom, PacketRouter packetRouter) {
this.room = chatroom;
this.router = packetRouter;
}
......@@ -170,7 +170,7 @@ public class IQAdminHandler {
for (MUCRole role : room.getModerators()) {
metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin");
metaData.addAttribute("role", "moderator");
metaData.addAttribute("jid", role.getChatUser().getAddress().toString());
metaData.addAttribute("jid", role.getUserAddress().toString());
metaData.addAttribute("nick", role.getNickname());
metaData.addAttribute("affiliation", role.getAffiliation().toString());
}
......@@ -183,7 +183,7 @@ public class IQAdminHandler {
for (MUCRole role : room.getParticipants()) {
metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin");
metaData.addAttribute("role", "participant");
metaData.addAttribute("jid", role.getChatUser().getAddress().toString());
metaData.addAttribute("jid", role.getUserAddress().toString());
metaData.addAttribute("nick", role.getNickname());
metaData.addAttribute("affiliation", role.getAffiliation().toString());
}
......@@ -219,7 +219,7 @@ public class IQAdminHandler {
else {
// Get the JID based on the requested nick
nick = item.attributeValue("nick");
jid = room.getOccupant(nick).getChatUser().getAddress();
jid = room.getOccupant(nick).getUserAddress();
}
room.lock.writeLock().lock();
......@@ -262,8 +262,7 @@ public class IQAdminHandler {
if (MUCRole.Role.moderator != senderRole.getRole()) {
throw new ForbiddenException();
}
presences.add(room.kickOccupant(jid,
senderRole.getChatUser().getAddress(),
presences.add(room.kickOccupant(jid, senderRole.getUserAddress(),
item.elementTextTrim("reason")));
}
}
......
......@@ -11,6 +11,10 @@
package org.jivesoftware.openfire.muc.spi;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.forms.DataForm;
import org.jivesoftware.openfire.forms.FormField;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
......@@ -18,18 +22,16 @@ import org.jivesoftware.openfire.forms.spi.XFormFieldImpl;
import org.jivesoftware.openfire.muc.ConflictException;
import org.jivesoftware.openfire.muc.ForbiddenException;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.openfire.*;
import org.jivesoftware.openfire.muc.cluster.RoomUpdatedEvent;
import org.jivesoftware.openfire.user.UserNotFoundException;
import java.util.*;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.cache.CacheFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;
import java.util.*;
/**
* A handler for the IQ packet with namespace http://jabber.org/protocol/muc#owner. This kind of
......@@ -39,7 +41,7 @@ import org.xmpp.packet.PacketError;
* @author Gaston Dombiak
*/
public class IQOwnerHandler {
private MUCRoomImpl room;
private LocalMUCRoom room;
private PacketRouter router;
......@@ -47,7 +49,7 @@ public class IQOwnerHandler {
private Element probeResult;
public IQOwnerHandler(MUCRoomImpl chatroom, PacketRouter packetRouter) {
public IQOwnerHandler(LocalMUCRoom chatroom, PacketRouter packetRouter) {
this.room = chatroom;
this.router = packetRouter;
init();
......@@ -209,7 +211,7 @@ public class IQOwnerHandler {
else {
// Get the bare JID based on the requested nick
nick = item.attributeValue("nick");
bareJID = room.getOccupant(nick).getChatUser().getAddress().toBareJID();
bareJID = room.getOccupant(nick).getUserAddress().toBareJID();
}
jids.put(bareJID, affiliation);
}
......@@ -313,6 +315,10 @@ public class IQOwnerHandler {
if (room.isLocked() && !room.isManuallyLocked()) {
room.unlock(senderRole);
}
if (!room.isDestroyed) {
// Let other cluster nodes that the room has been updated
CacheFactory.doClusterTask(new RoomUpdatedEvent(room));
}
}
}
......
......@@ -12,12 +12,12 @@
package org.jivesoftware.openfire.muc.spi;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.muc.MUCRole;
import org.jivesoftware.openfire.muc.MUCRoom;
import org.jivesoftware.openfire.muc.MultiUserChatServer;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
......@@ -144,7 +144,7 @@ public class MUCPersistenceManager {
*
* @param room the room to load from the database if persistent
*/
public static void loadFromDB(MUCRoomImpl room) {
public static void loadFromDB(LocalMUCRoom room) {
Connection con = null;
PreparedStatement pstmt = null;
try {
......@@ -294,7 +294,7 @@ public class MUCPersistenceManager {
*
* @param room The room to save its configuration.
*/
public static void saveToDB(MUCRoomImpl room) {
public static void saveToDB(LocalMUCRoom room) {
Connection con = null;
PreparedStatement pstmt = null;
try {
......@@ -415,19 +415,19 @@ public class MUCPersistenceManager {
* @param packetRouter the PacketRouter that loaded rooms will use to send packets.
* @return a collection with all the persistent rooms.
*/
public static Collection<MUCRoom> loadRoomsFromDB(MultiUserChatServer chatserver,
public static Collection<LocalMUCRoom> loadRoomsFromDB(MultiUserChatServer chatserver,
Date emptyDate, PacketRouter packetRouter) {
Connection con = null;
PreparedStatement pstmt = null;
Map<Long,MUCRoom> rooms = new HashMap<Long,MUCRoom>();
Map<Long, LocalMUCRoom> rooms = new HashMap<Long, LocalMUCRoom>();
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_ALL_ROOMS);
pstmt.setString(1, StringUtils.dateToMillis(emptyDate));
ResultSet rs = pstmt.executeQuery();
MUCRoomImpl room = null;
LocalMUCRoom room = null;
while (rs.next()) {
room = new MUCRoomImpl(chatserver, rs.getString(4), packetRouter);
room = new LocalMUCRoom(chatserver, rs.getString(4), packetRouter);
room.setID(rs.getLong(1));
room.setCreationDate(new Date(Long.parseLong(rs.getString(2).trim()))); // creation date
room.setModificationDate(new Date(Long.parseLong(rs.getString(3).trim()))); // modification date
......@@ -478,7 +478,7 @@ public class MUCPersistenceManager {
// Load the rooms conversations from the last two days
rs = pstmt.executeQuery();
while (rs.next()) {
room = (MUCRoomImpl) rooms.get(rs.getLong(1));
room = (LocalMUCRoom) rooms.get(rs.getLong(1));
// Skip to the next position if the room does not exist
if (room == null) {
continue;
......@@ -521,7 +521,7 @@ public class MUCPersistenceManager {
long roomID = rs.getLong(1);
String jid = rs.getString(2);
MUCRole.Affiliation affiliation = MUCRole.Affiliation.valueOf(rs.getInt(3));
room = (MUCRoomImpl) rooms.get(roomID);
room = (LocalMUCRoom) rooms.get(roomID);
// Skip to the next position if the room does not exist
if (room == null) {
continue;
......@@ -552,7 +552,7 @@ public class MUCPersistenceManager {
pstmt = con.prepareStatement(LOAD_ALL_MEMBERS);
rs = pstmt.executeQuery();
while (rs.next()) {
room = (MUCRoomImpl) rooms.get(rs.getLong(1));
room = (LocalMUCRoom) rooms.get(rs.getLong(1));
// Skip to the next position if the room does not exist
if (room == null) {
continue;
......@@ -626,7 +626,7 @@ public class MUCPersistenceManager {
*
* @param room the room to update its lock status in the database.
*/
public static void updateRoomLock(MUCRoomImpl room) {
public static void updateRoomLock(LocalMUCRoom room) {
if (!room.isPersistent() || !room.wasSavedToDB()) {
return;
}
......
......@@ -73,8 +73,7 @@ public class ClientRoute implements Cacheable, Externalizable {
nodeID = XMPPServer.getInstance().getNodeID();
}
else {
// TODO Keep singleton instances in NodeID
nodeID = new NodeID(bytes);
nodeID = NodeID.getInstance(bytes);
}
available = ExternalizableUtil.getInstance().readBoolean(in);
}
......
......@@ -134,6 +134,16 @@ public class CacheFactory {
}
}
/**
* Returns a byte[] that uniquely identifies this senior cluster member or <tt>null</tt>
* when not in a cluster.
*
* @return a byte[] that uniquely identifies this senior cluster member or null when not in a cluster.
*/
public static byte[] getSeniorClusterMemberID() {
return cacheFactoryStrategy.getSeniorClusterMemberID();
}
/**
* Returns true if this member is the senior member in the cluster. If clustering
* is not enabled, this method will also return true. This test is useful for
......
......@@ -52,6 +52,14 @@ public interface CacheFactoryStrategy {
*/
boolean isSeniorClusterMember();
/**
* Returns a byte[] that uniquely identifies this senior cluster member or <tt>null</tt>
* when not in a cluster.
*
* @return a byte[] that uniquely identifies this senior cluster member or null when not in a cluster.
*/
byte[] getSeniorClusterMemberID();
/**
* Returns a byte[] that uniquely identifies this member within the cluster or <tt>null</tt>
* when not in a cluster.
......
......@@ -159,6 +159,10 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy {
return true;
}
public byte[] getSeniorClusterMemberID() {
return null;
}
public byte[] getClusterMemberID() {
return new byte[0];
}
......
......@@ -9,9 +9,9 @@
- Use is subject to license terms.
--%>
<%@ page import="org.jivesoftware.util.ParamUtils,
org.jivesoftware.openfire.muc.MUCRole,
<%@ page import="org.jivesoftware.openfire.muc.MUCRole,
org.jivesoftware.openfire.muc.MUCRoom,
org.jivesoftware.util.ParamUtils,
java.net.URLEncoder,
java.text.DateFormat"
errorPage="error.jsp"
......@@ -87,7 +87,7 @@
<tbody>
<% for (MUCRole role : room.getOccupants()) { %>
<tr>
<td><%= role.getChatUser().getAddress() %></td>
<td><%= role.getUserAddress() %></td>
<td><%= role.getNickname() %></td>
<td><%= role.getRole() %></td>
<td><%= role.getAffiliation() %></td>
......
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