Commit b3a18c22 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gaston

Refactoring work. Simplified Roster & RosterItem hierarchies to have only two...

Refactoring work. Simplified Roster & RosterItem hierarchies to have only two classes: Roster & RosterItem.


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@743 b35dd754-fafc-0310-a699-88a17e54d16e
parent 65b06fa0
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.User;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
......@@ -110,25 +109,22 @@ public interface PresenceManager {
*
* @param user the user to create a presence for.
* @return the presence for the user.
* @throws UnauthorizedException if not the user.
*/
public Presence createPresence(User user) throws UnauthorizedException;
public Presence createPresence(User user);
/**
* Sets a presence to be offline which causes the presence to be removed from the system.
*
* @param presence to presence to set to be offline.
* @throws UnauthorizedException if not the user.
*/
public void setOffline(Presence presence) throws UnauthorizedException;
public void setOffline(Presence presence);
/**
* Sets a user to be offline which causes the presence to be removed from the system.
*
* @param jid the user to set to be offline.
* @throws UnauthorizedException if not the user.
*/
public void setOffline(JID jid) throws UnauthorizedException;
public void setOffline(JID jid);
/**
* Probes the presence of the given XMPPAddress and attempts to send it to the given user.
......@@ -136,7 +132,7 @@ public interface PresenceManager {
* @param prober The user requesting the probe
* @param probee The XMPPAddress whos presence we would like sent have have probed
*/
public void probePresence(String prober, JID probee) throws UnauthorizedException;
public void probePresence(String prober, JID probee);
/**
* Probes the presence of the given XMPPAddress and attempts to send it to the given user.
......@@ -144,5 +140,5 @@ public interface PresenceManager {
* @param prober The user requesting the probe
* @param probee The XMPPAddress whos presence we would like sent have have probed
*/
public void probePresence(JID prober, JID probee) throws UnauthorizedException;
public void probePresence(JID prober, JID probee);
}
\ No newline at end of file
......@@ -157,7 +157,7 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
try {
User sessionUser = userManager.getUser(session.getUsername());
CachedRoster cachedRoster = (CachedRoster)sessionUser.getRoster();
Roster cachedRoster = sessionUser.getRoster();
if (IQ.Type.get == type) {
returnPacket = cachedRoster.getReset();
returnPacket.setType(IQ.Type.result);
......@@ -177,7 +177,7 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
else {
if (cachedRoster.isRosterItem(item.getJID())) {
// existing item
CachedRosterItem cachedItem = (CachedRosterItem)cachedRoster.getRosterItem(item.getJID());
RosterItem cachedItem = cachedRoster.getRosterItem(item.getJID());
cachedItem.setAsCopyOf(item);
cachedRoster.updateRosterItem(cachedItem);
}
......@@ -206,17 +206,15 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
* @param sender The JID of the sender of the removal request
* @param item The removal item element
*/
private void removeItem(org.jivesoftware.messenger.roster.Roster roster, JID sender, org.xmpp.packet.Roster.Item item)
throws UnauthorizedException
{
private void removeItem(org.jivesoftware.messenger.roster.Roster roster, JID sender,
org.xmpp.packet.Roster.Item item) {
JID recipient = item.getJID();
// Remove recipient from the sender's roster
roster.deleteRosterItem(item.getJID());
// Forward set packet to the subscriber
if (localServer.isLocal(recipient)) { // Recipient is local so let's handle it here
try {
CachedRoster recipientRoster = userManager.getUser(recipient.getNode()).getRoster();
Roster recipientRoster = userManager.getUser(recipient.getNode()).getRoster();
recipientRoster.deleteRosterItem(sender);
}
catch (UserNotFoundException e) {
......
......@@ -20,7 +20,6 @@ import org.jivesoftware.messenger.roster.Roster;
import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.*;
import org.jivesoftware.messenger.roster.spi.CachedRosterImpl;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Packet;
import org.xmpp.packet.JID;
......@@ -128,7 +127,7 @@ public class PresenceSubscribeHandler extends BasicModule implements ChannelHand
roster = (Roster)CacheManager.getCache("username2roster").get(username);
if (roster == null) {
// Not in cache so load a new one:
roster = new CachedRosterImpl(username);
roster = new Roster(username);
CacheManager.getCache("username2roster").put(username, roster);
}
}
......@@ -143,10 +142,9 @@ public class PresenceSubscribeHandler extends BasicModule implements ChannelHand
* @param target The roster target's jid (the item's jid to be changed)
* @param isSending True if the request is being sent by the owner
* @param type The subscription change type (subscribe, unsubscribe, etc.)
* @throws UnauthorizedException If a security access violation occurs
*/
private void manageSub(JID target, boolean isSending, Presence.Type type,
Roster roster) throws UnauthorizedException, UserAlreadyExistsException
Roster roster) throws UserAlreadyExistsException
{
try {
RosterItem item;
......@@ -156,9 +154,7 @@ public class PresenceSubscribeHandler extends BasicModule implements ChannelHand
else {
item = roster.createRosterItem(target);
}
//System.out.println("A " + item + " is " + item.getSubStatus() + " " + item.getAskStatus() + " " + item.getRecvStatus());
updateState(item, type, isSending);
//System.out.println("B " + item + " is " + item.getSubStatus() + " " + item.getAskStatus() + " " + item.getRecvStatus());
roster.updateRosterItem(item);
}
catch (UserNotFoundException e) {
......@@ -348,7 +344,7 @@ public class PresenceSubscribeHandler extends BasicModule implements ChannelHand
* @param action The new state change request
* @param isSending True if the roster owner of the item is sending the new state change request
*/
private static void updateState(RosterItem item, Presence.Type action, boolean isSending) throws UnauthorizedException {
private static void updateState(RosterItem item, Presence.Type action, boolean isSending) {
Map srTable = (Map)stateTable.get(item.getSubStatus());
Map changeTable = (Map)srTable.get(isSending ? "send" : "recv");
Change change = (Change)changeTable.get(action);
......
......@@ -18,8 +18,8 @@ import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.spi.SessionImpl;
import org.jivesoftware.messenger.roster.CachedRoster;
import org.jivesoftware.messenger.roster.RosterManager;
import org.jivesoftware.messenger.roster.Roster;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.*;
......@@ -175,7 +175,7 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
// Only user sessions need to be authenticated
if (!"".equals(session.getAddress().getNode())) {
String username = session.getAddress().getNode();
CachedRoster roster = rosterManager.getRoster(username);
Roster roster = rosterManager.getRoster(username);
Iterator items = roster.getRosterItems();
while (items.hasNext()) {
RosterItem item = (RosterItem)items.next();
......@@ -232,7 +232,7 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
try {
if (name != null && !"".equals(name)) {
name = name.toLowerCase();
CachedRoster roster = rosterManager.getRoster(name);
Roster roster = rosterManager.getRoster(name);
roster.broadcastPresence(update);
}
}
......@@ -297,7 +297,7 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
try {
if (name != null && !"".equals(name)) {
name = name.toLowerCase();
CachedRoster roster = rosterManager.getRoster(name);
Roster roster = rosterManager.getRoster(name);
// If the directed presence was sent to an entity that is not in the user's
// roster, keep a registry of this so that when the user goes offline we will
// be able to send the unavialable presence to the entity
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 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.
*/
package org.jivesoftware.messenger.roster;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.roster.Roster;
import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.Cacheable;
import org.xmpp.packet.JID;
/**
* <p>Implements the basic Roster interface storing all roster items into a simple hash table.</p>
* <p>This class is intended to be used as a simple based for creating specialized Roster
* implementations without having to recode the very boring item management.</p>
*
* @author Iain Shigeoka
*/
public class BasicRoster implements Roster, Cacheable {
/**
* <p>Roster item cache - table: key jabberid string; value roster item.</p>
*/
protected Hashtable rosterItems = new Hashtable();
/**
* <p>Lock for the roster item map.</p>
*/
private ReadWriteLock itemLock = new ReentrantReadWriteLock();
/**
* <p>Create an empty iq roster packet.</p>
*/
public BasicRoster() {
}
public boolean isRosterItem(JID user) {
itemLock.readLock().lock();
try {
return rosterItems.containsKey(user.toBareJID());
}
finally {
itemLock.readLock().unlock();
}
}
public Iterator getRosterItems() throws UnauthorizedException {
itemLock.readLock().lock();
try {
LinkedList itemList = new LinkedList();
Iterator items = rosterItems.values().iterator();
while (items.hasNext()) {
itemList.add(items.next());
}
return itemList.iterator();
}
finally {
itemLock.readLock().unlock();
}
}
public int getTotalRosterItemCount() throws UnauthorizedException {
itemLock.readLock().lock();
try {
return rosterItems.size();
}
finally {
itemLock.readLock().unlock();
}
}
public RosterItem getRosterItem(JID user) throws UnauthorizedException, UserNotFoundException {
itemLock.readLock().lock();
try {
RosterItem item = (RosterItem)rosterItems.get(user.toBareJID());
if (item == null) {
throw new UserNotFoundException(user.toBareJID());
}
return item;
}
finally {
itemLock.readLock().unlock();
}
}
public RosterItem createRosterItem(JID user) throws UnauthorizedException, UserAlreadyExistsException {
return createRosterItem(user, null, null);
}
public RosterItem createRosterItem(JID user, String nickname, List<String> groups)
throws UnauthorizedException, UserAlreadyExistsException {
RosterItem item = provideRosterItem(user, nickname, groups);
itemLock.writeLock().lock();
try {
rosterItems.put(item.getJid().toBareJID(), item);
return item;
}
finally {
itemLock.writeLock().unlock();
}
}
public void createRosterItem(org.xmpp.packet.Roster.Item item)
throws UnauthorizedException, UserAlreadyExistsException {
RosterItem rosterItem = provideRosterItem(item);
itemLock.writeLock().lock();
try {
rosterItems.put(item.getJID().toBareJID(), rosterItem);
}
finally {
itemLock.writeLock().unlock();
}
}
/**
* <p>Generate a new RosterItem for use with createRosterItem.<p>
* <p/>
* <p>Overriding classes will want to override this method to produce the roster
* item implementation to be used by the BasicRoster.createRsterItem() methods.</p>
*
* @param user The roster jid address to create the roster item for
* @param nickname The nickname to assign the item (or null for none)
* @param groups The groups the item belongs to (or null for none)
* @return The newly created roster items ready to be stored by the BasicRoster item's hash table
*/
protected RosterItem provideRosterItem(JID user, String nickname, List<String> groups)
throws UserAlreadyExistsException, UnauthorizedException {
return new BasicRosterItem(user, nickname, groups);
}
/**
* <p>Generate a new RosterItem for use with createRosterItem.<p>
* <p/>
* <p>Overriding classes will want to override this method to produce the roster
* item implementation to be used by the BasicRoster.createRsterItem() methods.</p>
*
* @param item The item to copy settings for the new item in this roster
* @return The newly created roster items ready to be stored by the BasicRoster item's hash table
*/
protected RosterItem provideRosterItem(org.xmpp.packet.Roster.Item item)
throws UserAlreadyExistsException, UnauthorizedException {
return new BasicRosterItem(item);
}
public void updateRosterItem(RosterItem item) throws UnauthorizedException, UserNotFoundException {
itemLock.writeLock().lock();
try {
if (rosterItems.get(item.getJid().toBareJID()) == null) {
throw new UserNotFoundException(item.getJid().toBareJID());
}
rosterItems.put(item.getJid().toBareJID(), item);
}
finally {
itemLock.writeLock().unlock();
}
}
public RosterItem deleteRosterItem(JID user) throws UnauthorizedException {
itemLock.writeLock().lock();
try {
// If removing the user was successful, remove the user from the subscriber list:
return (RosterItem)rosterItems.remove(user.toBareJID());
}
finally {
itemLock.writeLock().unlock();
}
}
public int getCachedSize() {
// Approximate the size of the object in bytes by calculating the size
// of each field.
int size = 0;
size += CacheSizes.sizeOfMap(rosterItems); // roster item cache
return size;
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 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.
*/
package org.jivesoftware.messenger.roster;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.xmpp.packet.JID;
import org.jivesoftware.messenger.roster.RosterItem;
/**
* <p>Implements the basic RosterItem interface storing all data into simple fields.</p>
* <p>This class is intended to be used as a simple based for creating specialized RosterItem
* implementations without having to recode the very boring and copies set/get accessor methods.</p>
*
* @author Iain Shigeoka
*/
public class BasicRosterItem implements RosterItem {
protected RecvType recvStatus;
protected JID jid;
protected String nickname;
protected List<String> groups;
protected SubType subStatus;
protected AskType askStatus;
public BasicRosterItem(JID jid,
SubType subStatus,
AskType askStatus,
RecvType recvStatus,
String nickname,
List<String> groups) {
this.jid = jid;
this.subStatus = subStatus;
this.askStatus = askStatus;
this.recvStatus = recvStatus;
this.nickname = nickname;
this.groups = new LinkedList<String>();
if (groups != null) {
Iterator<String> groupItr = groups.iterator();
while (groupItr.hasNext()) {
this.groups.add(groupItr.next());
}
}
}
public BasicRosterItem(JID jid) {
this(jid,
RosterItem.SUB_NONE,
RosterItem.ASK_NONE,
RosterItem.RECV_NONE,
null,
null);
}
public BasicRosterItem(JID jid, String nickname, List<String> groups) {
this(jid,
RosterItem.SUB_NONE,
RosterItem.ASK_NONE,
RosterItem.RECV_NONE,
nickname,
groups);
}
/**
* <p>Create a roster item from the data in another one.</p>
*
* @param item
*/
public BasicRosterItem(org.xmpp.packet.Roster.Item item) {
this(item.getJID(),
getSubType(item),
getAskStatus(item),
RosterItem.RECV_NONE,
item.getName(),
new LinkedList<String>(item.getGroups()));
}
private static RosterItem.AskType getAskStatus(org.xmpp.packet.Roster.Item item) {
if (item.getAsk() == org.xmpp.packet.Roster.Ask.subscribe) {
return RosterItem.ASK_SUBSCRIBE;
}
else if (item.getAsk() == org.xmpp.packet.Roster.Ask.unsubscribe) {
return RosterItem.ASK_UNSUBSCRIBE;
}
else {
return RosterItem.ASK_NONE;
}
}
private static RosterItem.SubType getSubType(org.xmpp.packet.Roster.Item item) {
if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.to) {
return RosterItem.SUB_TO;
}
else if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.from) {
return RosterItem.SUB_FROM;
}
else if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.both) {
return RosterItem.SUB_BOTH;
}
else if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.remove) {
return RosterItem.SUB_REMOVE;
}
else {
return RosterItem.SUB_NONE;
}
}
public SubType getSubStatus() {
return subStatus;
}
public void setSubStatus(SubType subStatus) {
this.subStatus = subStatus;
}
public AskType getAskStatus() {
return askStatus;
}
public void setAskStatus(AskType askStatus) {
this.askStatus = askStatus;
}
public RecvType getRecvStatus() {
return recvStatus;
}
public void setRecvStatus(RecvType recvStatus) {
this.recvStatus = recvStatus;
}
public JID getJid() {
return jid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public List<String> getGroups() {
return groups;
}
public void setGroups(List<String> groups) {
if (groups == null) {
this.groups = new LinkedList<String>();
}
else {
this.groups = groups;
}
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 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.
*/
package org.jivesoftware.messenger.roster;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.roster.*;
import org.jivesoftware.util.Cacheable;
import org.xmpp.packet.*;
import org.xmpp.packet.Roster;
/**
* <p>A Roster that is cached in memory and persisted to some backend storage system.</p>
* <p/>
* <p>Cached Rosters are the permanent roster attached to a user/chatbot account. This interface
* is primarily a marker interface for implementations.</p>
*
* @author Iain Shigeoka
* <p/>
*
*/
public interface CachedRoster extends org.jivesoftware.messenger.roster.Roster, Cacheable {
/**
* <p>Return the username of the user or chatbot that owns this roster.</p>
*
* @return the username of the user or chatbot that owns this roster
*/
String getUsername();
/**
* <p>Obtain a 'roster reset', a snapshot of the full cached roster as an Roster.</p>
*
* @return The roster reset (snapshot) as an Roster
*/
org.xmpp.packet.Roster getReset() throws UnauthorizedException;
/**
* <p>Broadcast the presence update to all subscribers of the roter.</p>
* <p/>
* <p>Any presence change typically results in a broadcast to the roster members.</p>
*
* @param packet The presence packet to broadcast
*/
void broadcastPresence(Presence packet);
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 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.
*/
package org.jivesoftware.messenger.roster;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.messenger.roster.RosterItem;
/**
* <p>Represents a persistently stored roster item.</p>
* <p/>
* <p>The interface is primarily a marker interface to differentiate
* the roster information passed around via XMPP XML roster packets,
* and the persistently stored roster associated with a particular account.</p>
*
* @author Iain Shigeoka
*/
public interface CachedRosterItem extends RosterItem, Cacheable {
/**
* <p>Obtain the roster ID associated with this particular roster item.</p>
* <p/>
* <p>Databases can use the roster ID as the key in locating roster items.</p>
*
* @return The roster ID
*/
public long getID();
/**
* <p>Update the cached item as a copy of the given item.</p>
* <p/>
* <p>A convenience for getting the item and setting each attribute.</p>
*
* @param item The item who's settings will be copied into the cached copy
*/
void setAsCopyOf(org.xmpp.packet.Roster.Item item);
}
......@@ -11,11 +11,14 @@
package org.jivesoftware.messenger.roster;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.IntEnum;
import org.jivesoftware.util.Cacheable;
import org.jivesoftware.util.CacheSizes;
import org.xmpp.packet.JID;
import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
/**
* <p>Represents a single roster item for a User's Roster.</p>
......@@ -30,11 +33,11 @@ import java.util.List;
* <li>groups - A list of groups to organize roster entries under (e.g. friends, co-workers, etc)</li>
* </ul>
*
* @author Iain Shigeoka
* @author Gaston Dombiak
*/
public interface RosterItem {
public class RosterItem implements Cacheable {
class SubType extends IntEnum {
public static class SubType extends IntEnum {
protected SubType(String name, int value) {
super(name, value);
register(this);
......@@ -45,7 +48,7 @@ public interface RosterItem {
}
}
class AskType extends IntEnum {
public static class AskType extends IntEnum {
protected AskType(String name, int value) {
super(name, value);
register(this);
......@@ -56,7 +59,7 @@ public interface RosterItem {
}
}
class RecvType extends IntEnum {
public static class RecvType extends IntEnum {
protected RecvType(String name, int value) {
super(name, value);
register(this);
......@@ -116,80 +119,227 @@ public interface RosterItem {
*/
public static final RecvType RECV_UNSUBSCRIBE = new RecvType("unsub", 2);
protected RecvType recvStatus;
protected JID jid;
protected String nickname;
protected List<String> groups;
protected SubType subStatus;
protected AskType askStatus;
private long rosterID;
public RosterItem(long id,
JID jid,
SubType subStatus,
AskType askStatus,
RecvType recvStatus,
String nickname,
List<String> groups) {
this(jid, subStatus, askStatus, recvStatus, nickname, groups);
this.rosterID = id;
}
public RosterItem(JID jid,
SubType subStatus,
AskType askStatus,
RecvType recvStatus,
String nickname,
List<String> groups) {
this.jid = jid;
this.subStatus = subStatus;
this.askStatus = askStatus;
this.recvStatus = recvStatus;
this.nickname = nickname;
this.groups = new LinkedList<String>();
if (groups != null) {
Iterator<String> groupItr = groups.iterator();
while (groupItr.hasNext()) {
this.groups.add(groupItr.next());
}
}
}
/**
* <p>Create a roster item from the data in another one.</p>
*
* @param item
*/
public RosterItem(org.xmpp.packet.Roster.Item item) {
this(item.getJID(),
getSubType(item),
getAskStatus(item),
RosterItem.RECV_NONE,
item.getName(),
new LinkedList<String>(item.getGroups()));
}
private static RosterItem.AskType getAskStatus(org.xmpp.packet.Roster.Item item) {
if (item.getAsk() == org.xmpp.packet.Roster.Ask.subscribe) {
return RosterItem.ASK_SUBSCRIBE;
}
else if (item.getAsk() == org.xmpp.packet.Roster.Ask.unsubscribe) {
return RosterItem.ASK_UNSUBSCRIBE;
}
else {
return RosterItem.ASK_NONE;
}
}
private static RosterItem.SubType getSubType(org.xmpp.packet.Roster.Item item) {
if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.to) {
return RosterItem.SUB_TO;
}
else if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.from) {
return RosterItem.SUB_FROM;
}
else if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.both) {
return RosterItem.SUB_BOTH;
}
else if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.remove) {
return RosterItem.SUB_REMOVE;
}
else {
return RosterItem.SUB_NONE;
}
}
/**
* <p>Obtain the current subscription status of the item.</p>
*
* @return The subscription status of the item
*/
public SubType getSubStatus();
public SubType getSubStatus() {
return subStatus;
}
/**
* <p>Set the current subscription status of the item.</p>
*
* @param subStatus The subscription status of the item
*/
public void setSubStatus(SubType subStatus) throws UnauthorizedException;
public void setSubStatus(SubType subStatus) {
this.subStatus = subStatus;
}
/**
* <p>Obtain the current ask status of the item.</p>
*
* @return The ask status of the item
*/
public AskType getAskStatus();
public AskType getAskStatus() {
return askStatus;
}
/**
* <p>Set the current ask status of the item.</p>
*
* @param askStatus The ask status of the item
*/
public void setAskStatus(AskType askStatus) throws UnauthorizedException;
public void setAskStatus(AskType askStatus) {
this.askStatus = askStatus;
}
/**
* <p>Obtain the current recv status of the item.</p>
*
* @return The recv status of the item
*/
public RecvType getRecvStatus();
public RecvType getRecvStatus() {
return recvStatus;
}
/**
* <p>Set the current recv status of the item.</p>
*
* @param recvStatus The recv status of the item
*/
public void setRecvStatus(RecvType recvStatus) throws UnauthorizedException;
public void setRecvStatus(RecvType recvStatus) {
this.recvStatus = recvStatus;
}
/**
* <p>Obtain the address of the item.</p>
*
* @return The address of the item
*/
public JID getJid();
public JID getJid() {
return jid;
}
/**
* <p>Obtain the current nickname for the item.</p>
*
* @return The subscription status of the item
*/
public String getNickname();
public String getNickname() {
return nickname;
}
/**
* <p>Set the current nickname for the item.</p>
*
* @param name The subscription status of the item
* @param nickname The subscription status of the item
*/
public void setNickname(String name) throws UnauthorizedException;
public void setNickname(String nickname) {
this.nickname = nickname;
}
/**
* <p>Obtain the groups for the item.</p>
*
* @return The subscription status of the item
*/
public List<String> getGroups();
public List<String> getGroups() {
return groups;
}
/**
* <p>Set the current groups for the item.</p>
*
* @param groups The subscription status of the item
*/
public void setGroups(List<String> groups) throws UnauthorizedException;
public void setGroups(List<String> groups) {
if (groups == null) {
this.groups = new LinkedList<String>();
}
else {
this.groups = groups;
}
}
/**
* <p>Obtain the roster ID associated with this particular roster item.</p>
* <p/>
* <p>Databases can use the roster ID as the key in locating roster items.</p>
*
* @return The roster ID
*/
public long getID() {
return rosterID;
}
public void setID(long rosterID) {
this.rosterID = rosterID;
}
/**
* <p>Update the cached item as a copy of the given item.</p>
* <p/>
* <p>A convenience for getting the item and setting each attribute.</p>
*
* @param item The item who's settings will be copied into the cached copy
*/
public void setAsCopyOf(org.xmpp.packet.Roster.Item item) {
setNickname(item.getName());
setGroups(new LinkedList<String>(item.getGroups()));
}
public int getCachedSize() {
int size = jid.toBareJID().length();
size += CacheSizes.sizeOfString(nickname);
size += CacheSizes.sizeOfCollection(groups);
size += CacheSizes.sizeOfInt(); // subStatus
size += CacheSizes.sizeOfInt(); // askStatus
size += CacheSizes.sizeOfLong(); // id
return size;
}
}
\ No newline at end of file
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger.roster;
import org.jivesoftware.messenger.roster.spi.CachedRosterItemImpl;
import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.database.DbConnectionManager;
......@@ -85,12 +84,11 @@ public class RosterItemProvider {
* @param item the settings for the roster item to create
* @return The created roster item
*/
public CachedRosterItem createItem(String username, RosterItem item)
public RosterItem createItem(String username, RosterItem item)
throws UserAlreadyExistsException
{
Connection con = null;
PreparedStatement pstmt = null;
CachedRosterItem cachedItem = null;
try {
con = DbConnectionManager.getConnection();
......@@ -105,15 +103,7 @@ public class RosterItemProvider {
pstmt.setString(7, item.getNickname());
pstmt.executeUpdate();
if (item instanceof CachedRosterItemImpl) {
// If a RosterItemImpl we can reuse it by setting the new roster ID
cachedItem = (CachedRosterItem)item;
((CachedRosterItemImpl)cachedItem).setID(rosterID);
}
else {
// Otherwise, just create a coyy of the item with the new roster ID
cachedItem = new CachedRosterItemImpl(rosterID, item);
}
item.setID(rosterID);
insertGroups(rosterID, item.getGroups().iterator(), pstmt, con);
}
catch (SQLException e) {
......@@ -125,7 +115,7 @@ public class RosterItemProvider {
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
return cachedItem;
return item;
}
/**
......@@ -137,7 +127,7 @@ public class RosterItemProvider {
* @param item The roster item to update
* @throws org.jivesoftware.messenger.user.UserNotFoundException If no entry could be found to update
*/
public void updateItem(String username, CachedRosterItem item) throws UserNotFoundException {
public void updateItem(String username, RosterItem item) throws UserNotFoundException {
Connection con = null;
PreparedStatement pstmt = null;
long rosterID = item.getID();
......@@ -292,7 +282,7 @@ public class RosterItemProvider {
// TODO: this code must be refactored ASAP. Not legal to have two open pstmts
// TODO: on many databases.
while (rs.next()) {
CachedRosterItem item = new CachedRosterItemImpl(rs.getLong(2),
RosterItem item = new RosterItem(rs.getLong(2),
new JID(rs.getString(1)),
RosterItem.SubType.getTypeFromInt(rs.getInt(3)),
RosterItem.AskType.getTypeFromInt(rs.getInt(4)),
......
......@@ -15,9 +15,7 @@ import org.xmpp.packet.JID;
import org.jivesoftware.util.Cache;
import org.jivesoftware.util.CacheManager;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.roster.spi.CachedRosterImpl;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import java.util.Iterator;
......@@ -48,17 +46,17 @@ public class RosterManager extends BasicModule {
* @throws org.jivesoftware.messenger.user.UserNotFoundException if the ID does not correspond to a known
* entity on the server.
*/
public CachedRoster getRoster(String username) throws UserNotFoundException {
public Roster getRoster(String username) throws UserNotFoundException {
if (rosterCache == null) {
rosterCache = CacheManager.getCache("username2roster");
}
if (rosterCache == null) {
throw new UserNotFoundException("Could not load caches");
}
CachedRoster roster = (CachedRoster)rosterCache.get(username);
Roster roster = (Roster)rosterCache.get(username);
if (roster == null) {
// Not in cache so load a new one:
roster = new CachedRosterImpl(username);
roster = new Roster(username);
rosterCache.put(username, roster);
}
if (roster == null) {
......@@ -80,7 +78,7 @@ public class RosterManager extends BasicModule {
Roster roster = (Roster)CacheManager.getCache("username2roster").get(username);
if (roster == null) {
// Not in cache so load a new one:
roster = new CachedRosterImpl(username);
roster = new Roster(username);
}
// Remove each roster item from the user's roster
Iterator<RosterItem> items = roster.getRosterItems();
......@@ -99,7 +97,7 @@ public class RosterManager extends BasicModule {
roster = (Roster)CacheManager.getCache("username2roster").get(username);
if (roster == null) {
// Not in cache so load a new one:
roster = new CachedRosterImpl(username);
roster = new Roster(username);
}
// Remove the deleted user reference from this roster
roster.deleteRosterItem(user);
......@@ -108,8 +106,5 @@ public class RosterManager extends BasicModule {
catch (UnsupportedOperationException e) {
// Do nothing
}
catch (UnauthorizedException e) {
// Do nothing
}
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 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.
*/
package org.jivesoftware.messenger.roster.spi;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import org.jivesoftware.messenger.ChannelHandler;
import org.jivesoftware.messenger.PresenceManager;
import org.jivesoftware.messenger.RoutingTable;
import org.jivesoftware.messenger.SessionManager;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.roster.BasicRoster;
import org.jivesoftware.messenger.roster.BasicRosterItem;
import org.jivesoftware.messenger.roster.CachedRoster;
import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.roster.CachedRosterItem;
import org.jivesoftware.messenger.roster.*;
import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.util.CacheSizes;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Roster;
/**
* <p>A roster implemented against a JDBC database.</p>
* <p/>
* <p>Updates to this roster is effectively a change to the user or chatbot
* account's roster. To reflect this, the changes to this class will
* will automatically update the persistently stored roster, as well as
* send out update announcements to all logged in user sessions.</p>
*
* @author Iain Shigeoka
*/
public class CachedRosterImpl extends BasicRoster implements CachedRoster {
private RosterItemProvider rosterItemProvider;
private String username;
private SessionManager sessionManager;
private XMPPServer server;
private RoutingTable routingTable;
/**
* <p>Create a roster for the given user, pulling the existing roster items
* out of the backend storage provider.</p>
*
* @param username The username of the user that owns this roster
*/
public CachedRosterImpl(String username) {
sessionManager = SessionManager.getInstance();
this.username = username;
rosterItemProvider = RosterItemProvider.getInstance();
Iterator items = rosterItemProvider.getItems(username);
while (items.hasNext()) {
RosterItem item = (RosterItem)items.next();
rosterItems.put(item.getJid().toBareJID(), item);
}
}
public String getUsername() {
return username;
}
public Roster getReset() throws UnauthorizedException {
Roster roster = new Roster();
Iterator items = getRosterItems();
while (items.hasNext()) {
RosterItem item = (RosterItem)items.next();
if (item.getSubStatus() != RosterItem.SUB_NONE || item.getAskStatus() != RosterItem.ASK_NONE) {
roster.addItem(item.getJid(), item.getNickname(),
getAskStatus(item.getAskStatus()),
Roster.Subscription.valueOf(item.getSubStatus().getName()),
item.getGroups());
}
}
return roster;
}
private Roster.Ask getAskStatus(RosterItem.AskType askType) {
if ("".equals(askType.getName())) {
return null;
}
return Roster.Ask.valueOf(askType.getName());
}
public void broadcastPresence(Presence packet) {
try {
if (routingTable == null) {
routingTable = XMPPServer.getInstance().getRoutingTable();
}
if (routingTable == null) {
return;
}
Iterator items = getRosterItems();
while (items.hasNext()) {
RosterItem item = (RosterItem)items.next();
if (item.getSubStatus() == RosterItem.SUB_BOTH
|| item.getSubStatus() == RosterItem.SUB_FROM) {
JID searchNode = new JID(item.getJid().getNode(), item.getJid().getDomain(), null);
Iterator sessions = routingTable.getRoutes(searchNode);
packet.setTo(item.getJid());
while (sessions.hasNext()) {
ChannelHandler session = (ChannelHandler)sessions.next();
try {
session.process(packet);
}
catch (Exception e) {
// Ignore any problems with sending - theoretically
// only happens if session has been closed
}
}
}
}
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
protected RosterItem provideRosterItem(org.xmpp.packet.Roster.Item item)
throws UserAlreadyExistsException, UnauthorizedException {
return provideRosterItem(item.getJID(), item.getName(),
new ArrayList<String>(item.getGroups()));
}
protected RosterItem provideRosterItem(JID user, String nickname, List<String> group) throws UserAlreadyExistsException, UnauthorizedException {
Roster roster = new Roster();
roster.setType(IQ.Type.set);
Roster.Item item = roster.addItem(user, nickname, null, Roster.Subscription.none, group);
RosterItem rosterItem = rosterItemProvider.createItem(username, new BasicRosterItem(item));
// Broadcast the roster push to the user
broadcast(roster);
return rosterItem;
}
private PresenceManager presenceManager;
public void updateRosterItem(RosterItem item) throws UnauthorizedException, UserNotFoundException {
CachedRosterItem cachedItem = null;
if (item instanceof CachedRosterItem) {
// This is a known item
cachedItem = (CachedRosterItem)item;
}
else {
// This is a different item object, probably a BasicRosterItem update for an existing
// item. So grab the cached version out of the super to learn the rosterID for the item
// And create a new cached roster item with the new info
cachedItem = (CachedRosterItem)super.getRosterItem(item.getJid());
cachedItem = new CachedRosterItemImpl(cachedItem.getID(), item);
}
// Update the super first, this will throw a UserNotFoundException if the entry doesn't
// already exist
super.updateRosterItem(cachedItem);
// Update the backend data store
rosterItemProvider.updateItem(username, cachedItem);
// broadcast roster update
if (!(cachedItem.getSubStatus() == RosterItem.SUB_NONE
&& cachedItem.getAskStatus() == RosterItem.ASK_NONE)) {
Roster roster = new Roster();
roster.setType(IQ.Type.set);
roster.addItem(cachedItem.getJid(), cachedItem.getNickname(),
getAskStatus(cachedItem.getAskStatus()),
Roster.Subscription.valueOf(cachedItem.getSubStatus().getName()),
cachedItem.getGroups());
broadcast(roster);
}
if (cachedItem.getSubStatus() == RosterItem.SUB_BOTH
|| cachedItem.getSubStatus() == RosterItem.SUB_TO) {
if (presenceManager == null) {
presenceManager = XMPPServer.getInstance().getPresenceManager();
}
presenceManager.probePresence(username, cachedItem.getJid());
}
}
public RosterItem deleteRosterItem(JID user) throws UnauthorizedException {
// Note that the super cache will always only hold cached roster items
CachedRosterItem item = (CachedRosterItem)super.deleteRosterItem(user);
if (item != null) {
// If removing the user was successful, remove the user from the backend store
rosterItemProvider.deleteItem(username, item.getID());
// Broadcast the update to the user
Roster roster = new Roster();
roster.setType(IQ.Type.set);
roster.addItem(user, Roster.Subscription.remove);
broadcast(roster);
}
return item;
}
private void broadcast(Roster roster) throws UnauthorizedException {
if (server == null) {
server = XMPPServer.getInstance();
}
JID recipient = server.createJID(username, null);
roster.setTo(recipient);
if (sessionManager == null) {
sessionManager = SessionManager.getInstance();
}
sessionManager.userBroadcast(username, roster);
}
public int getCachedSize() {
// Approximate the size of the object in bytes by calculating the size
// of each field.
int size = 0;
size += CacheSizes.sizeOfObject(); // overhead of object
size += CacheSizes.sizeOfString(username); // username
try {
Iterator itemIter = getRosterItems();
while (itemIter.hasNext()) {
CachedRosterItem item = (CachedRosterItem)itemIter.next();
size += item.getCachedSize();
}
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
return size;
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 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.
*/
package org.jivesoftware.messenger.roster.spi;
import java.util.List;
import java.util.LinkedList;
import org.jivesoftware.messenger.roster.BasicRosterItem;
import org.jivesoftware.messenger.roster.CachedRosterItem;
import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.roster.CachedRosterItem;
import org.jivesoftware.util.CacheSizes;
import org.xmpp.packet.JID;
/**
* In-memory implementation of a roster item. The ID of the roster item is it's roster ID.
*
* @author Iain Shigeoka
*/
public class CachedRosterItemImpl extends BasicRosterItem implements CachedRosterItem {
public CachedRosterItemImpl(long id,
JID jid,
SubType subStatus,
AskType askStatus,
RecvType recvStatus,
String nickname,
List<String> groups) {
super(jid, subStatus, askStatus, recvStatus, nickname, groups);
this.rosterID = id;
}
public CachedRosterItemImpl(long id, JID jid) {
this(id,
jid,
RosterItem.SUB_NONE,
RosterItem.ASK_NONE,
RosterItem.RECV_NONE,
null,
null);
}
public CachedRosterItemImpl(long id, JID jid, String nickname, List<String> groups) {
this(id,
jid,
RosterItem.SUB_NONE,
RosterItem.ASK_NONE,
RosterItem.RECV_NONE,
nickname,
groups);
}
/**
* <p>Create a roster item from the data in another one.</p>
*
* @param id
* @param item
*/
public CachedRosterItemImpl(long id, RosterItem item) {
this(id,
item.getJid(),
item.getSubStatus(),
item.getAskStatus(),
item.getRecvStatus(),
item.getNickname(),
item.getGroups());
}
private long rosterID;
public void setID(long rosterID) {
this.rosterID = rosterID;
}
public long getID() {
return rosterID;
}
public void setAsCopyOf(org.xmpp.packet.Roster.Item item) {
setNickname(item.getName());
setGroups(new LinkedList<String>(item.getGroups()));
}
public int getCachedSize() {
int size = jid.toBareJID().length();
size += CacheSizes.sizeOfString(nickname);
size += CacheSizes.sizeOfList(groups);
size += CacheSizes.sizeOfInt(); // subStatus
size += CacheSizes.sizeOfInt(); // askStatus
size += CacheSizes.sizeOfLong(); // id
return size;
}
}
......@@ -226,7 +226,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
}
}
public void setOffline(JID jid) throws UnauthorizedException {
public void setOffline(JID jid) {
}
public boolean isAvailable(User user) {
......
......@@ -11,7 +11,7 @@
package org.jivesoftware.messenger.user;
import org.jivesoftware.messenger.roster.CachedRoster;
import org.jivesoftware.messenger.roster.Roster;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.Cacheable;
......@@ -235,7 +235,7 @@ public class User implements Cacheable {
*
* @return the user's roster.
*/
public CachedRoster getRoster() {
public Roster getRoster() {
try {
return XMPPServer.getInstance().getRosterManager().getRoster(username);
}
......
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