Merge "Issue #2785 - Change connection order of events Fixed classpath Change-Id: I15296306ee105a54379a370da7d53c7e46dc34bb" into development

Former-commit-id: 323e6beb3e [formerly 44f93acd4d] [formerly 847481950c] [formerly ea3a8e29c3 [formerly 847481950c [formerly 2f4d6ca7b78e40d11a3dbfd66969681ddd2135fd]]]
Former-commit-id: ea3a8e29c3
Former-commit-id: 2d66ea60e65694f8edb4f2b29eaafcecb6c33f34 [formerly e99ad67ada]
Former-commit-id: 7a9f211997
This commit is contained in:
Nate Jensen 2014-04-09 08:50:45 -05:00 committed by Gerrit Code Review
commit d252a00965
10 changed files with 594 additions and 561 deletions

View file

@ -19,6 +19,7 @@
**/
package com.raytheon.uf.viz.collaboration.comm.identity.roster;
import com.raytheon.uf.viz.collaboration.comm.provider.session.ISubscriptionRequestCompleteAction;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**
@ -34,6 +35,8 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Jan 27, 2014 2700 bclement handle subscribe request returns a boolean
* all methods take user id instead of qualified id
* Feb 13, 2014 2755 bclement handleSubscribeRequest now returns SubscriptionResponse
* Apr 07, 2014 2785 mpduff Remove return type from and add parameter to handleSubscribeRequest
* Removed unused methods
*
* </pre>
*
@ -47,22 +50,8 @@ public interface ISubscriptionResponder {
* Triggered when a contact requests a presence subscription
*
* @param fromID
* @return true if the subscribe request is accepted.
* @param action
*/
public SubscriptionResponse handleSubscribeRequest(UserId fromID);
/**
* Triggered when a contact subscribes to user
*
* @param fromID
*/
public void handleSubscribed(UserId fromID);
/**
* Triggered when a contact unsubscribes to user
*
* @param fromID
*/
public void handleUnsubscribed(UserId fromID);
public void handleSubscribeRequest(UserId fromID,
ISubscriptionRequestCompleteAction action);
}

View file

@ -22,31 +22,19 @@ package com.raytheon.uf.viz.collaboration.comm.provider.session;
import java.util.Arrays;
import java.util.Map;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster.SubscriptionMode;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.IAccountManager;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IRosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.ISubscriptionResponder;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.SubscriptionResponse;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.event.UserPresenceChangedEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**
@ -71,6 +59,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Jan 31, 2014 2700 bclement fixed subscribe back after accepting subscription
* Feb 12, 2014 2797 bclement added protective copy to sendPresence
* Feb 13, 2014 2755 bclement added user input for which group to add contact to
* Apr 07, 2014 2785 mpduff Moved PacketListener implementation to its own class
*
* </pre>
*
@ -80,139 +69,28 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
public class AccountManager implements IAccountManager {
private final IUFStatusHandler log = UFStatus.getHandler(this.getClass());
/**
* Listens for subscription events including subscription requests. If the
* subscription responder is null, the default action is to accept
* subscription requests.
*/
private PacketListener subscriptionEventListener = new PacketListener() {
@Override
public void processPacket(Packet packet) {
if ( packet instanceof Presence){
Presence pres = (Presence) packet;
Type type = pres.getType();
if (type == null) {
return;
}
UserId fromId = IDConverter.convertFrom(pres.getFrom());
switch (type) {
case subscribe:
SubscriptionResponse response;
if (responder != null) {
response = responder.handleSubscribeRequest(fromId);
} else {
response = new SubscriptionResponse(true);
}
handleSubRequest(fromId, response);
break;
case subscribed:
if (responder != null) {
responder.handleSubscribed(fromId);
}
handleSubscribed(fromId);
break;
case unsubscribed:
if (responder != null) {
responder.handleUnsubscribed(fromId);
}
handleUnsubscribed(fromId);
break;
default:
// do nothing
break;
}
}
}
/**
* notify UI that someone subscribed to user
*
* @param fromID
*/
private void handleSubscribed(UserId fromID) {
ContactsManager cm = sessionManager.getContactsManager();
RosterEntry entry = cm.getRosterEntry((UserId) fromID);
IRosterChangeEvent event = new RosterChangeEvent(
RosterChangeType.ADD, entry);
sessionManager.postEvent(event);
}
/**
* notify UI that someone unsubscribed to user
*
* @param fromID
*/
private void handleUnsubscribed(UserId fromID) {
ContactsManager cm = sessionManager.getContactsManager();
RosterEntry entry = cm.getRosterEntry((UserId) fromID);
if (entry == null) {
return;
}
IRosterChangeEvent event = new RosterChangeEvent(
RosterChangeType.DELETE, entry);
sessionManager.postEvent(event);
}
/**
* process subscription request
*
* @param fromId
*/
private void handleSubRequest(UserId fromId,
SubscriptionResponse response) {
Presence.Type subscribedType;
ContactsManager cm = sessionManager.getContactsManager();
boolean addToRoster = false;
if (response.isAccepted()) {
subscribedType = Presence.Type.subscribed;
RosterEntry entry = cm.getRosterEntry(fromId);
if (entry == null) {
addToRoster = true;
}
} else {
subscribedType = Presence.Type.unsubscribed;
}
Presence presence = new Presence(subscribedType);
try {
sendPresence(fromId, presence);
if (addToRoster) {
if (response.addToGroup()) {
cm.addToGroup(response.getGroup(), fromId);
} else {
cm.addToRoster(fromId);
}
}
} catch (CollaborationException e) {
AccountManager.this.log.error("Unable to send presence", e);
}
}
};
private ISubscriptionResponder responder;
private CollaborationConnection sessionManager = null;
private org.jivesoftware.smack.AccountManager smackManager;
private final org.jivesoftware.smack.AccountManager smackManager;
private final SubscriptionPacketListener subscriptionEventListener;
/**
*
* @param adapter
*/
AccountManager(
CollaborationConnection manager) {
AccountManager(CollaborationConnection manager) {
sessionManager = manager;
subscriptionEventListener = new SubscriptionPacketListener(
sessionManager);
XMPPConnection xmppConnection = manager.getXmppConnection();
smackManager = new org.jivesoftware.smack.AccountManager(
xmppConnection);
smackManager = new org.jivesoftware.smack.AccountManager(xmppConnection);
xmppConnection.getRoster().setSubscriptionMode(SubscriptionMode.manual);
sessionManager.getXmppConnection().addPacketListener(subscriptionEventListener,
new PacketTypeFilter(Presence.class));
sessionManager.getXmppConnection()
.addPacketListener(subscriptionEventListener,
new PacketTypeFilter(Presence.class));
}
/*
@ -232,6 +110,7 @@ public class AccountManager implements IAccountManager {
@Override
public void setSubscriptionRequestResponder(ISubscriptionResponder responder) {
this.responder = responder;
subscriptionEventListener.setResponder(responder);
}
/**
@ -241,6 +120,7 @@ public class AccountManager implements IAccountManager {
@Override
public void removeSubscriptionRequestResponder() {
responder = null;
subscriptionEventListener.setResponder(responder);
}
/**
@ -340,11 +220,11 @@ public class AccountManager implements IAccountManager {
* @param userPresence
* @throws CollaborationException
*/
@Override
public void sendPresence(UserId toId, Presence userPresence)
throws CollaborationException {
userPresence.setFrom(sessionManager.getUser().getFQName());
userPresence.setTo(toId.getNormalizedId());
sessionManager.getXmppConnection().sendPacket(userPresence);
}
}

View file

@ -37,8 +37,6 @@ import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Mode;
import org.jivesoftware.smack.packet.Presence.Type;
import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.provider.ProviderManager;
@ -119,6 +117,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Feb 28, 2014 2756 bclement added authManager
* Mar 07, 2014 2848 bclement removed join*Venue methods, now only creates venue objects
* changed session map to a concurrent hash map
* Apr 07, 2014 2785 mpduff Changed the order of startup, sets up listeners before actually connecting.
*
* </pre>
*
@ -144,9 +143,9 @@ public class CollaborationConnection implements IEventPublisher {
private static Map<CollaborationConnectionData, CollaborationConnection> instanceMap = new HashMap<CollaborationConnectionData, CollaborationConnection>();
private final Map<String, ISession> sessions;
private Map<String, ISession> sessions;
private final UserId user;
private UserId user;
private Presence userPresence;
@ -154,17 +153,17 @@ public class CollaborationConnection implements IEventPublisher {
private IAccountManager accountManager = null;
private final EventBus eventBus;
private EventBus eventBus;
private final ContactsManager contactsMgr;
private ContactsManager contactsMgr;
private final CollaborationConnectionData connectionData;
private XMPPConnection connection;
private final ClientAuthManager authManager;
private ClientAuthManager authManager;
public static boolean COMPRESS = true;
private static boolean COMPRESS = true;
static {
try {
@ -181,15 +180,13 @@ public class CollaborationConnection implements IEventPublisher {
private CollaborationConnection(CollaborationConnectionData connectionData)
throws CollaborationException {
this.connectionData = connectionData;
String password = connectionData.getPassword();
Mode mode = connectionData.getStatus();
if (mode == null) {
mode = Mode.available;
}
Presence initialPresence = new Presence(Type.available,
connectionData.getMessage(), 0, mode);
Tools.setProperties(initialPresence, connectionData.getAttributes());
init();
}
/**
* Initialize this object.
*/
private void init() throws CollaborationException {
eventBus = new EventBus();
sessions = new ConcurrentHashMap<String, ISession>();
@ -205,29 +202,17 @@ public class CollaborationConnection implements IEventPublisher {
conConfig.setCompressionEnabled(COMPRESS);
connection = new XMPPConnection(conConfig);
connectInternal(connectionData.getUserName(), password);
accountManager = new AccountManager(this);
this.user = new UserId(connectionData.getUserName(),
connection.getServiceName());
setupConnectionListener();
setupAccountManager();
setupInternalConnectionListeners();
setupInternalVenueInvitationListener();
setupP2PComm();
getPeerToPeerSession();
authManager = new ClientAuthManager(connection);
userPresence = initialPresence;
if (accountManager != null && initialPresence != null) {
accountManager.sendPresence(initialPresence);
}
contactsMgr = new ContactsManager(this, connection);
this.registerEventHandler(contactsMgr);
instanceMap.put(connectionData, this);
if (instance == null) {
instance = this;
@ -278,7 +263,6 @@ public class CollaborationConnection implements IEventPublisher {
/**
* @return
* @see com.raytheon.uf.viz.collaboration.comm.identity.roster.IRoster#getUser()
*/
public UserId getUser() {
return user;
@ -294,32 +278,18 @@ public class CollaborationConnection implements IEventPublisher {
/**
*
* @return
* @param presence
*/
public void setPresence(Presence presence) {
userPresence = presence;
}
/**
*
*/
private void setupAccountManager() {
if (accountManager == null) {
if (isConnected()) {
accountManager = new AccountManager(this);
}
}
}
/**
* Get the account manager for this connection.
*
* @return The account manager for this connection.
*/
public IAccountManager getAccountManager() {
if (accountManager == null) {
setupAccountManager();
}
return accountManager;
}
@ -374,6 +344,7 @@ public class CollaborationConnection implements IEventPublisher {
* Get the PeerToPeerChat session instance.
*
* @return
* @throws CollaborationException
*/
public ISession getPeerToPeerSession() throws CollaborationException {
if (chatInstance == null) {
@ -427,7 +398,6 @@ public class CollaborationConnection implements IEventPublisher {
*
* @param data
* @return
* @throws CollaborationException
*/
public SharedDisplaySession createCollaborationVenue(CreateSessionData data) {
SharedDisplaySession session = new SharedDisplaySession(eventBus, this,
@ -445,7 +415,6 @@ public class CollaborationConnection implements IEventPublisher {
* @param venueName
* @param handle
* @return
* @throws CollaborationException
*/
public VenueSession createTextOnlyVenue(String venueName, String handle) {
return createTextOnlyVenue(new CreateSessionData(venueName, handle));
@ -557,11 +526,9 @@ public class CollaborationConnection implements IEventPublisher {
}
private void setupP2PComm() {
if (isConnected()) {
PeerToPeerCommHelper helper = new PeerToPeerCommHelper(this);
connection.addPacketListener(helper, new PacketTypeFilter(
Message.class));
}
PeerToPeerCommHelper helper = new PeerToPeerCommHelper(this);
connection.addPacketListener(helper,
new PacketTypeFilter(Message.class));
}
private void setupConnectionListener() {
@ -750,14 +717,15 @@ public class CollaborationConnection implements IEventPublisher {
* @return
* @throws CollaborationException
*/
public static CollaborationConnection connect(
public static CollaborationConnection createConnection(
CollaborationConnectionData userData) throws CollaborationException {
if (instance != null) {
throw new CollaborationException("Already connected");
} else {
instance = new CollaborationConnection(userData);
return getConnection();
}
instance = new CollaborationConnection(userData);
return getConnection();
}
/**
@ -795,4 +763,19 @@ public class CollaborationConnection implements IEventPublisher {
return authManager;
}
/**
* Connect to the XMPP server. This needs to be called after the
* CollaborationConnection has been created and initialized.
*
* @throws CollaborationException
*/
public void connect() throws CollaborationException {
contactsMgr = new ContactsManager(this, this.getXmppConnection());
registerEventHandler(instance.getContactsManager());
connectInternal(connectionData.getUserName(),
connectionData.getPassword());
authManager = new ClientAuthManager(getXmppConnection());
}
}

View file

@ -0,0 +1,53 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.SubscriptionResponse;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**
* Interface for post request actions.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 04, 2014 2785 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public interface ISubscriptionRequestCompleteAction {
/**
* Called after subscription request is complete.
*
* @param userId
* The originating userId
* @param response
* The response
*/
public void executeSubscriptionRequestComplete(UserId userId,
SubscriptionResponse response);
}

View file

@ -0,0 +1,193 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IRosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.ISubscriptionResponder;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.SubscriptionResponse;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager;
import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
/**
* Listens for subscription events including subscription requests. If the
* subscription responder is null, the default action is to accept subscription
* requests.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 04, 2014 2785 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class SubscriptionPacketListener implements PacketListener,
ISubscriptionRequestCompleteAction {
private static final IUFStatusHandler log = UFStatus
.getHandler(SubscriptionPacketListener.class);
/**
* The responder for this listener.
*/
private ISubscriptionResponder responder;
/**
* The CollaborationConnection for his listener.
*/
private CollaborationConnection sessionManager = null;
/**
* Constructor.
*
* @param sessionManager
* The CollaborationConnection to use
*/
public SubscriptionPacketListener(CollaborationConnection sessionManager) {
this.sessionManager = sessionManager;
}
/**
* {@inheritDoc}
*/
@Override
public void processPacket(Packet packet) {
if (packet instanceof Presence) {
Presence pres = (Presence) packet;
Type type = pres.getType();
if (type == null) {
return;
}
UserId fromId = IDConverter.convertFrom(pres.getFrom());
switch (type) {
case subscribe:
responder.handleSubscribeRequest(fromId, this);
break;
case subscribed:
handleSubscribed(fromId);
break;
case unsubscribed:
handleUnsubscribed(fromId);
break;
default:
// do nothing
break;
}
}
}
/**
* notify UI that someone subscribed to user
*
* @param fromID
*/
private void handleSubscribed(UserId fromID) {
ContactsManager cm = sessionManager.getContactsManager();
RosterEntry entry = cm.getRosterEntry(fromID);
IRosterChangeEvent event = new RosterChangeEvent(RosterChangeType.ADD,
entry);
sessionManager.postEvent(event);
}
/**
* notify UI that someone unsubscribed to user
*
* @param fromID
*/
private void handleUnsubscribed(UserId fromID) {
ContactsManager cm = sessionManager.getContactsManager();
RosterEntry entry = cm.getRosterEntry(fromID);
if (entry == null) {
return;
}
IRosterChangeEvent event = new RosterChangeEvent(
RosterChangeType.DELETE, entry);
sessionManager.postEvent(event);
}
/**
* process subscription request
*
* @param fromId
*/
private void handleSubResponse(UserId fromId, SubscriptionResponse response) {
Presence.Type subscribedType;
ContactsManager cm = sessionManager.getContactsManager();
boolean addToRoster = false;
if (response.isAccepted()) {
subscribedType = Presence.Type.subscribed;
RosterEntry entry = cm.getRosterEntry(fromId);
if (entry == null) {
addToRoster = true;
}
} else {
subscribedType = Presence.Type.unsubscribed;
}
Presence presence = new Presence(subscribedType);
try {
sendPresence(fromId, presence);
if (addToRoster) {
if (response.addToGroup()) {
cm.addToGroup(response.getGroup(), fromId);
} else {
cm.addToRoster(fromId);
}
}
} catch (CollaborationException e) {
log.error("Unable to send presence", e);
}
}
private void sendPresence(UserId toId, Presence userPresence) {
userPresence.setFrom(sessionManager.getUser().getFQName());
userPresence.setTo(toId.getNormalizedId());
sessionManager.getXmppConnection().sendPacket(userPresence);
}
@Override
public void executeSubscriptionRequestComplete(UserId userId,
SubscriptionResponse response) {
handleSubResponse(userId, response);
}
public void setResponder(ISubscriptionResponder responder) {
this.responder = responder;
}
}

View file

@ -44,8 +44,8 @@ import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConn
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.ui.actions.PeerToPeerChatAction;
import com.raytheon.uf.viz.collaboration.ui.jobs.AwayTimeOut;
import com.raytheon.uf.viz.collaboration.ui.prefs.AutoSubscribePropertyListener;
import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;
import com.raytheon.uf.viz.collaboration.ui.prefs.SubscriptionResponderImpl;
import com.raytheon.uf.viz.collaboration.ui.session.CollaborationSessionView;
import com.raytheon.uf.viz.collaboration.ui.session.PeerToPeerView;
import com.raytheon.uf.viz.collaboration.ui.session.SessionView;
@ -69,6 +69,7 @@ import com.raytheon.viz.ui.views.CaveWorkbenchPageManager;
* Jan 30, 2014 2698 bclement moved xmpp join logic to dialog so we can reprompt user on failure
* Feb 13, 2014 2751 bclement messages return IUser instead of IQualifiedID
* Mar 06, 2014 2848 bclement moved SharedDisplaySessionMgr.joinSession call to InviteDialog
* Apr 08, 2014 2785 mpduff removed preference listener
*
* </pre>
*
@ -88,11 +89,6 @@ public class ConnectionSubscriber {
private final AwayTimeOut awayTimeOut = new AwayTimeOut();
private ConnectionSubscriber() {
Activator
.getDefault()
.getPreferenceStore()
.addPropertyChangeListener(
AutoSubscribePropertyListener.getInstance());
}
/**
@ -124,9 +120,8 @@ public class ConnectionSubscriber {
private void setup(final CollaborationConnection connection) {
if (connection != null) {
AutoSubscribePropertyListener autoSub = AutoSubscribePropertyListener
.getInstance();
autoSub.initialize(connection);
connection.getAccountManager().setSubscriptionRequestResponder(
new SubscriptionResponderImpl(connection));
// Register handlers and events for the new sessionManager.
connection.registerEventHandler(this);
try {
@ -170,9 +165,6 @@ public class ConnectionSubscriber {
"Error unregistering peer to peer handler", e);
}
connection.unregisterEventHandler(this);
AutoSubscribePropertyListener autoSub = AutoSubscribePropertyListener
.getInstance();
autoSub.close();
}
PlatformUI.getWorkbench().removeWorkbenchListener(wbListener);
}
@ -193,7 +185,8 @@ public class ConnectionSubscriber {
IVenueSession session = inviteBox.getSession();
if (inviteBox.isSharedDisplay()) {
CaveWorkbenchPageManager.getActiveInstance().showView(
CollaborationSessionView.ID, session.getSessionId(),
CollaborationSessionView.ID,
session.getSessionId(),
IWorkbenchPage.VIEW_ACTIVATE);
} else {
CaveWorkbenchPageManager.getActiveInstance().showView(

View file

@ -19,28 +19,30 @@
**/
package com.raytheon.uf.viz.collaboration.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.jivesoftware.smack.RosterGroup;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
/**
* Dialog to respond to a chat subscription request
* Dialog to respond to a chat subscription request. Returns the name of the
* group if accepted, null for denial of request.
*
* <pre>
*
@ -51,94 +53,90 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Jan 27, 2014 2700 bclement Initial creation
* Jan 31, 2014 2700 bclement don't prompt for group if user is already in one
* Feb 13, 2014 2755 bclement roster addition now done in account manager, user input passed back
* Apr 07, 2014 2785 mpduff Changed to implement CaveSWTDialog
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class SubRequestDialog extends Dialog {
public class SubRequestDialog extends CaveSWTDialog {
private final String NEW_GROUP = "New Group...";
private final String title;
private final String userid;
private final String message;
private final UserId userid;
private Combo groupCombo;
private String group;
private Combo groupCbo;
/**
* Constructor
*
* @param parentShell
* @param userid
*/
public SubRequestDialog(Shell parentShell, String title, String message,
UserId userid) {
super(parentShell);
this.title = title;
this.message = message;
public SubRequestDialog(Shell parentShell, String userid) {
super(parentShell, SWT.DIALOG_TRIM);
this.userid = userid;
setText("Contact Request");
}
/**
* @param parentShell
*/
public SubRequestDialog(IShellProvider parentShell, String title,
String message, UserId userid) {
super(parentShell);
this.title = title;
this.message = message;
this.userid = userid;
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
*/
@Override
protected void buttonPressed(int buttonId) {
if (buttonId == IDialogConstants.OK_ID) {
int count = groupCombo.getItemCount();
int index = groupCombo.getSelectionIndex();
if ( index == count - 1){
// new group
CreateGroupDialog dialog = new CreateGroupDialog(Display
.getCurrent().getActiveShell());
dialog.open();
group = dialog.getNewGroup();
} else if ( index >= 0){
group = groupCombo.getItem(index);
protected void initializeComponents(Shell shell) {
GridLayout gl = new GridLayout(1, false);
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
Composite mainComp = new Composite(shell, SWT.NONE);
mainComp.setLayout(gl);
mainComp.setLayoutData(gd);
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
Label msgLbl = new Label(mainComp, SWT.NONE);
msgLbl.setText(userid + " wants to add you to their contacts list.");
msgLbl.setLayoutData(gd);
gl = new GridLayout(2, false);
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
Composite groupComp = new Composite(mainComp, SWT.NONE);
groupComp.setLayout(gl);
groupComp.setLayoutData(gd);
gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false);
Label groupLbl = new Label(groupComp, SWT.NONE);
groupLbl.setText("Group: ");
groupLbl.setLayoutData(gd);
groupCbo = new Combo(groupComp, SWT.DROP_DOWN | SWT.READ_ONLY);
groupCbo.setItems(getGroupNames());
groupCbo.select(0);
groupCbo.setLayout(gl);
groupCbo.setLayoutData(gd);
gl = new GridLayout(2, false);
gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
Composite btnComp = new Composite(mainComp, SWT.NONE);
btnComp.setLayout(gl);
btnComp.setLayoutData(gd);
int btnWidth = 75;
gd = new GridData(btnWidth, SWT.DEFAULT);
Button allowBtn = new Button(btnComp, SWT.PUSH);
allowBtn.setText("Allow");
allowBtn.setLayoutData(gd);
allowBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
action(true);
}
}
super.buttonPressed(buttonId);
}
});
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
new Label(container, SWT.NONE).setText(message);
Composite groupComposite = new Composite(container, SWT.NONE);
groupComposite.setLayout(new GridLayout(2, false));
groupComposite.setLayoutData(new GridData(SWT.LEFT, SWT.DEFAULT,
true, false));
new Label(groupComposite, SWT.NONE).setText("Group: ");
groupCombo = new Combo(groupComposite, SWT.BORDER | SWT.READ_ONLY
| SWT.DROP_DOWN);
groupCombo.setItems(getGroupNames());
CollaborationConnection conn = CollaborationConnection.getConnection();
Collection<RosterGroup> groups = conn.getContactsManager().getGroups(
userid);
if (!groups.isEmpty()) {
// we already have this user in a group in our roster, no need to
// prompt
groupComposite.setVisible(false);
}
return container;
gd = new GridData(btnWidth, SWT.DEFAULT);
Button denyBtn = new Button(btnComp, SWT.PUSH);
denyBtn.setText("Deny");
denyBtn.setLayoutData(gd);
denyBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
action(false);
}
});
}
/**
@ -152,43 +150,39 @@ public class SubRequestDialog extends Dialog {
}
Collection<RosterGroup> groups = connection.getContactsManager()
.getGroups();
String[] rval = new String[groups.size() + 1];
Iterator<RosterGroup> iter = groups.iterator();
int i = 0;
for (; iter.hasNext(); ++i) {
rval[i] = iter.next().getName();
List<String> groupList = new ArrayList<String>(groups.size());
for (String group : groupList) {
groupList.add(group);
}
rval[i] = "New Group...";
return rval;
}
/* (non-Javadoc)
* @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
*/
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(title);
}
Collections.sort(groupList);
groupList.add(0, NEW_GROUP);
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse
* .swt.widgets.Composite)
*/
@Override
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, "Allow", true);
createButton(parent, IDialogConstants.CANCEL_ID, "Deny", false);
return groupList.toArray(new String[groupList.size()]);
}
/**
* @return the group
* Action handler.
*
* @param approved
* true if request approved, false if denied
*/
public String getGroup() {
return group;
}
private void action(boolean approved) {
if (approved) {
if (groupCbo.getSelectionIndex() == 0) {
// new group
CreateGroupDialog dialog = new CreateGroupDialog(Display
.getCurrent().getActiveShell());
dialog.open();
String group = dialog.getNewGroup();
setReturnValue(group);
} else {
setReturnValue(groupCbo.getItem(groupCbo.getSelectionIndex()));
}
} else {
setReturnValue(null);
}
close();
}
}

View file

@ -43,6 +43,7 @@ import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Mode;
import org.jivesoftware.smack.packet.Presence.Type;
import com.google.common.collect.Iterators;
import com.raytheon.uf.common.status.UFStatus.Priority;
@ -50,6 +51,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation.HostConfig;
import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformation.SiteConfig;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnectionData;
import com.raytheon.uf.viz.collaboration.ui.Activator;
@ -72,6 +74,7 @@ import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;
* Jan 06, 2014 2563 bclement moved server text parsing to ServerInput class
* Jan 08, 2014 2563 bclement added Add/Remove buttons for server list
* Jan 15, 2014 2630 bclement connection data stores status as Mode object
* Apr 07, 2014 2785 mpduff Implemented change to CollaborationConnection
*
* </pre>
*
@ -81,9 +84,9 @@ import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;
public class LoginDialog extends Dialog {
private IPreferenceStore preferences;
private final IPreferenceStore preferences;
private CollaborationConnectionData loginData;
private final CollaborationConnectionData loginData;
private Text userText;
@ -156,9 +159,7 @@ public class LoginDialog extends Dialog {
// Server setting
new Label(body, SWT.NONE).setText("Server: ");
serverText = new Combo(body, SWT.BORDER | SWT.READ_ONLY
| SWT.DROP_DOWN);
serverText = new Combo(body, SWT.BORDER | SWT.READ_ONLY | SWT.DROP_DOWN);
gd = new GridData(SWT.FILL, SWT.FILL, true, true);
gd.minimumWidth = 200;
serverText.setLayoutData(gd);
@ -198,14 +199,14 @@ public class LoginDialog extends Dialog {
addServerButton = new Button(serverButtons, SWT.PUSH);
addServerButton.setText(ServerListListener.addButtonText);
addServerButton.setLayoutData(gd);
addServerButton.addListener(SWT.Selection, new ServerListListener(serverText));
addServerButton.addListener(SWT.Selection, new ServerListListener(
serverText));
removeServerButton = new Button(serverButtons, SWT.PUSH);
removeServerButton.setText(ServerListListener.removeButtonText);
removeServerButton.setLayoutData(gd);
removeServerButton.addListener(SWT.Selection, new ServerListListener(
serverText));
// Password setting
new Label(body, SWT.NONE).setText("Password: ");
passwordText = new Text(body, SWT.PASSWORD | SWT.BORDER);
@ -365,11 +366,33 @@ public class LoginDialog extends Dialog {
messageBox.open();
} else {
try {
CollaborationConnection connection = CollaborationConnection
.connect(loginData);
ConnectionSubscriber.subscribe(connection);
// Create the connection
CollaborationConnection collabConnection = CollaborationConnection
.createConnection(loginData);
// Subscribe to the collaboration connection
ConnectionSubscriber.subscribe(collabConnection);
// Connect to the XMPP server
collabConnection.connect();
storeLoginData();
shell.dispose();
// send initial presence
Mode mode = loginData.getStatus();
if (mode == null) {
mode = Mode.available;
}
Presence initialPresence = new Presence(Type.available,
loginData.getMessage(), 0, mode);
Tools.setProperties(initialPresence,
loginData.getAttributes());
collabConnection.getAccountManager().sendPresence(
initialPresence);
} catch (CollaborationException e) {
Activator.statusHandler.handle(Priority.PROBLEM,
"Error connecting to collaboration server: "

View file

@ -1,225 +0,0 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.ui.prefs;
import org.eclipse.jface.preference.IPersistentPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.jivesoftware.smack.XMPPException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.identity.IAccountManager;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.ISubscriptionResponder;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.SubscriptionResponse;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserSearch;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.SubRequestDialog;
import com.raytheon.uf.viz.core.VizApp;
/**
* Listens to collaboration preferences and alters the subscription request
* handler as appropriate.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 24, 2014 2700 bclement Initial creation
* Feb 3, 2014 2699 bclement fixed assumption that username search was exact
* Feb 13, 2014 2755 bclement added user input for which group to add contact to
* Mar 12, 2014 2632 mpduff Property change to handle String and Boolean
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class AutoSubscribePropertyListener implements IPropertyChangeListener {
private static final IUFStatusHandler log = UFStatus
.getHandler(AutoSubscribePropertyListener.class);
private static AutoSubscribePropertyListener instance;
private static final Object INSTANCE_MUTEX = new Object();
public static AutoSubscribePropertyListener getInstance() {
synchronized (INSTANCE_MUTEX) {
if (instance == null) {
instance = new AutoSubscribePropertyListener();
}
}
return instance;
}
private CollaborationConnection connection;
private IAccountManager accountManager;
private AutoSubscribePropertyListener() {
}
/**
* Initialize auto subscribe state after login
*
* @param connection
*/
public synchronized void initialize(CollaborationConnection connection) {
this.connection = connection;
this.accountManager = connection.getAccountManager();
updateManager(isAutoInPrefs());
}
/**
* Clean up auto subscribe state after logout
*/
public synchronized void close() {
this.accountManager = null;
this.connection = null;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse
* .jface.util.PropertyChangeEvent)
*/
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(
CollabPrefConstants.AUTO_ACCEPT_SUBSCRIBE)
&& accountManager != null) {
// The HierarchicalPreferenceStore store sometimes returns a string
Object valueObject = event.getNewValue();
if (valueObject instanceof Boolean) {
updateManager((Boolean) valueObject);
} else {
updateManager(Boolean.valueOf(valueObject.toString()));
}
}
}
/**
* @return true if preferences have auto accept enabled
*/
private boolean isAutoInPrefs() {
IPersistentPreferenceStore prefs = Activator.getDefault()
.getPreferenceStore();
return prefs.getBoolean(CollabPrefConstants.AUTO_ACCEPT_SUBSCRIBE);
}
/**
* Update auto subscribe state in account manager
*
* @param auto
*/
private void updateManager(boolean auto) {
// manager auto accepts by default if responder is not set
boolean accountManagerAutoAccepts = !accountManager
.isSubscriptionRequestResponderSet();
// update if the settings don't match
if (auto != accountManagerAutoAccepts) {
if (auto) {
accountManager.removeSubscriptionRequestResponder();
} else {
accountManager.setSubscriptionRequestResponder(newResponder());
}
}
}
/**
* Create responder to handle subscription requests
*
* @return
*/
private ISubscriptionResponder newResponder() {
return new ISubscriptionResponder() {
private final UserSearch search = connection.createSearch();
@Override
public void handleUnsubscribed(UserId fromID) {
}
@Override
public void handleSubscribed(UserId fromID) {
}
@Override
public SubscriptionResponse handleSubscribeRequest(
final UserId fromID) {
String displayName = getDisplayName(fromID);
StringBuilder builder = new StringBuilder();
builder.append(fromID.getFQName());
if (displayName != null) {
builder.append(" (").append(displayName).append(")");
}
builder.append(" wants to add you to his or her contacts list.");
final String msg = builder.toString();
final SubscriptionResponse rval = new SubscriptionResponse();
VizApp.runSync(new Runnable() {
@Override
public void run() {
Shell shell = new Shell(Display.getCurrent());
SubRequestDialog dlg = new SubRequestDialog(shell,
"Authorize Collaboration Contact", msg, fromID);
int index = dlg.open();
rval.setAccepted(index == Window.OK);
rval.setGroup(dlg.getGroup());
}
});
return rval;
}
/**
* Get display name for user from server
*
* @param fromID
* @return null if none found
*/
private String getDisplayName(UserId fromID) {
String rval = null;
try {
UserId user = search.byExactUsername(fromID.getName());
return user != null ? user.getAlias() : null;
} catch (XMPPException e) {
log.error("Unable to get display name for user: " + fromID,
e);
}
return rval;
}
};
}
}

View file

@ -0,0 +1,150 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.ui.prefs;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jface.preference.IPersistentPreferenceStore;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.XMPPException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.ISubscriptionResponder;
import com.raytheon.uf.viz.collaboration.comm.identity.roster.SubscriptionResponse;
import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.session.ISubscriptionRequestCompleteAction;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserSearch;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.SubRequestDialog;
import com.raytheon.uf.viz.core.VizApp;
/**
* The subscription responder impelementation.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 03, 2014 2785 mpduff Initial creation
*
* </pre>
*
* @author mpduff
* @version 1.0
*/
public class SubscriptionResponderImpl implements ISubscriptionResponder {
/**
* Log instance
*/
private final IUFStatusHandler log = UFStatus.getHandler(this.getClass());
/**
* Map tracking user contact requests
*/
private final Set<String> subRequest = Collections
.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
/**
* Search instance
*/
private final UserSearch search;
public SubscriptionResponderImpl(CollaborationConnection connection) {
this.search = connection.createSearch();
}
@Override
public void handleSubscribeRequest(final UserId fromID,
final ISubscriptionRequestCompleteAction action) {
final SubscriptionResponse rval = new SubscriptionResponse();
IPersistentPreferenceStore prefs = Activator.getDefault()
.getPreferenceStore();
if (prefs.getBoolean(CollabPrefConstants.AUTO_ACCEPT_SUBSCRIBE)) {
rval.setAccepted(true);
action.executeSubscriptionRequestComplete(fromID, rval);
return;
}
CollaborationConnection conn = CollaborationConnection.getConnection();
Collection<RosterGroup> groups = conn.getContactsManager().getGroups(
fromID);
if (!groups.isEmpty()) {
// we already have this user in a group in our roster
rval.setAccepted(true);
action.executeSubscriptionRequestComplete(fromID, rval);
} else {
Boolean dlgExists = subRequest.contains(fromID.getFQName());
if (!dlgExists) {
subRequest.add(fromID.getFQName());
VizApp.runAsync(new Runnable() {
@Override
public void run() {
String displayName = getDisplayName(fromID);
Shell shell = new Shell(Display.getCurrent());
SubRequestDialog dlg = new SubRequestDialog(shell,
displayName);
Object returnVal = dlg.open();
if (returnVal == null) {
// Denied
rval.setAccepted(false);
rval.setGroup(null);
} else {
if (returnVal instanceof String) {
rval.setAccepted(true);
rval.setGroup((String) returnVal);
}
}
subRequest.remove(fromID.getFQName());
action.executeSubscriptionRequestComplete(fromID, rval);
}
});
}
}
}
/**
* Get display name for user from server
*
* @param fromID
* @return null if none found
*/
private String getDisplayName(UserId fromID) {
String rval = null;
try {
UserId user = search.byExactUsername(fromID.getName());
return user != null ? user.getAlias() : null;
} catch (XMPPException e) {
log.error("Unable to get display name for user: " + fromID, e);
}
return rval;
}
}