Merge "Issue #2822 shared display invitations always go to cave" into development

Former-commit-id: 2b20cf5440 [formerly ad6e4712d6 [formerly 2a61b602d55922e5b7f5002f794449880c2cc1a7]]
Former-commit-id: ad6e4712d6
Former-commit-id: 827112349a
This commit is contained in:
Nate Jensen 2014-04-23 15:30:44 -05:00 committed by Gerrit Code Review
commit 68e3650305
8 changed files with 484 additions and 61 deletions

View file

@ -19,6 +19,7 @@
**/
package com.raytheon.uf.viz.collaboration.comm;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
@ -34,6 +35,7 @@ import com.raytheon.uf.common.comm.NetworkStatistics;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 27, 2012 jkorman Initial creation
* Apr 23, 2014 2822 bclement added getBundleVersion()
*
* </pre>
*
@ -80,4 +82,20 @@ public class Activator implements BundleActivator {
return plugin;
}
/**
* Get the version from the manifest
*
* @return null if not available
*/
public static String getBundleVersion(){
String rval = null;
if ( plugin != null){
BundleContext context = plugin.getContext();
if ( context != null){
Bundle bundle = context.getBundle();
rval = bundle.getVersion().toString();
}
}
return rval;
}
}

View file

@ -45,6 +45,7 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.common.xmpp.iq.AuthInfo;
import com.raytheon.uf.common.xmpp.iq.AuthInfoProvider;
import com.raytheon.uf.viz.collaboration.comm.Activator;
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;
@ -113,6 +114,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Apr 14, 2014 2903 bclement moved from session subpackage to connection, removed password from memory,
* moved listeners to own classes, reworked connect/register listeners/login order
* Apr 15, 2014 2822 bclement added pubsub owner subscriptions provider registration
* Apr 23, 2014 2822 bclement added resource name and getCollaborationVersion()
*
* </pre>
*
@ -144,6 +146,8 @@ public class CollaborationConnection implements IEventPublisher {
PubSubNamespace.OWNER.getXmlns(), new SubscriptionsProvider());
}
private static final String RESOURCE_BASENAME = "CAVE";
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(CollaborationConnection.class);
@ -303,7 +307,7 @@ public class CollaborationConnection implements IEventPublisher {
private void loginInternal(String username, String password)
throws CollaborationException {
try {
connection.login(username, password);
connection.login(username, password, getResourceName());
} catch (XMPPException e) {
close();
// get a nice reason for the user
@ -333,6 +337,28 @@ public class CollaborationConnection implements IEventPublisher {
}
}
/**
* get name used for CAVE collaboration XMPP resource
*
* @return
*/
public static String getResourceName() {
String rval = RESOURCE_BASENAME;
String version = getCollaborationVersion();
if (version != null) {
rval += "-" + version;
}
return rval;
}
/**
* @see Activator#getBundleVersion()
* @return
*/
public static String getCollaborationVersion() {
return Activator.getBundleVersion();
}
/**
* @return login data used to create this connection
*/

View file

@ -67,6 +67,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.account.ClientAuthManager
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.PeerToPeerCommHelper;
import com.raytheon.uf.viz.collaboration.comm.provider.event.LeaderChangeEvent;
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;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
@ -99,6 +100,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Apr 15, 2014 2822 bclement added check for other participants being subscribed to topic
* Apr 21, 2014 2822 bclement removed use of resources in topicSubscribers, added skipCache
* Apr 22, 2014 2903 bclement added connection test to closePubSub() method
* Apr 23, 2014 2822 bclement added formatInviteAddress()
*
* </pre>
*
@ -802,4 +804,31 @@ public class SharedDisplaySession extends VenueSession implements
return rval;
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.viz.collaboration.comm.provider.session.VenueSession#
* formatInviteAddress
* (com.raytheon.uf.viz.collaboration.comm.provider.user.UserId)
*/
@Override
protected String formatInviteAddress(UserId id) {
CollaborationConnection manager = getConnection();
ContactsManager cm = manager.getContactsManager();
String resource = cm.getSharedDisplayEnabledResource(id);
/*
* resource will be null if we can't find a resource that supports
* shared displays for this user
*/
String rval;
if (resource == null) {
rval = super.formatInviteAddress(id);
} else {
UserId newId = new UserId(id.getName(), id.getHost(), resource);
rval = newId.getFQName();
}
return rval;
}
}

View file

@ -110,6 +110,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Apr 16, 2014 3020 bclement added check for invited rooms in roomExistsOnServer()
* Apr 21, 2014 2822 bclement added hasMultipleHandles()
* Apr 22, 2014 2903 bclement added connection test to close method
* Apr 23, 2014 2822 bclement added formatInviteAddress()
*
*
* </pre>
@ -225,7 +226,6 @@ public class VenueSession extends BaseSession implements IVenueSession {
SessionPayload payload = new SessionPayload(PayloadType.Invitation,
invite);
Message msg = new Message();
msg.setTo(id.getNormalizedId());
UserId user = getAccount();
msg.setFrom(user.getNormalizedId());
msg.setType(Type.normal);
@ -236,7 +236,17 @@ public class VenueSession extends BaseSession implements IVenueSession {
} else if (!StringUtils.isBlank(invite.getSubject())) {
reason = invite.getSubject();
}
muc.invite(msg, id.getNormalizedId(), reason);
muc.invite(msg, formatInviteAddress(id), reason);
}
/**
* format invite address for user
*
* @param id
* @return
*/
protected String formatInviteAddress(UserId id) {
return id.getNormalizedId();
}
/*

View file

@ -0,0 +1,242 @@
/**
* 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.user;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
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.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
/**
* Keeps track of contacts and resource information. Responsible for sending out
* roster change events.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 22, 2014 2822 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ContactsListener implements RosterListener {
private final ContactsManager manager;
private final Roster roster;
private final Map<String, List<ResourceInfo>> contactResources = new HashMap<String, List<ResourceInfo>>();
/**
* @param manager
* @param roster
*/
public ContactsListener(ContactsManager manager, Roster roster) {
this.manager = manager;
this.roster = roster;
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.RosterListener#presenceChanged(org.jivesoftware
* .smack.packet.Presence)
*/
@Override
public void presenceChanged(Presence presence) {
String fromId = presence.getFrom();
UserId u = IDConverter.convertFrom(fromId);
if (u != null) {
synchronized (contactResources) {
/* if they are logging out */
if (presence.getType() == Type.unavailable) {
processLogout(u);
} else {
processUpdate(u, presence);
}
}
RosterEntry entry = manager.getRosterEntry(u);
post(entry);
IRosterChangeEvent event = new RosterChangeEvent(
RosterChangeType.PRESENCE, entry, presence);
post(event);
}
}
/**
* Update contact resources when resource logs out. Must be externally
* synchronized
*
* @param uid
*/
private void processLogout(UserId uid) {
String bareId = uid.getNormalizedId();
List<ResourceInfo> resources = contactResources.get(bareId);
if (resources != null) {
String resource = uid.getResource();
Iterator<ResourceInfo> iterator = resources.iterator();
while (iterator.hasNext()) {
ResourceInfo next = iterator.next();
if (next.getResourceName().equalsIgnoreCase(resource)) {
iterator.remove();
}
}
if (resources.isEmpty()) {
contactResources.remove(bareId);
}
}
}
/**
* Update contact resources when resource changes (non-logout). Must be
* externally synchronized.
*
* @param uid
* @param presence
*/
private void processUpdate(UserId uid, Presence presence) {
String bareId = uid.getNormalizedId();
String resource = uid.getResource();
List<ResourceInfo> resources = contactResources.get(bareId);
if (resources == null) {
/* we don't expect a large number of clients per user */
resources = new ArrayList<ResourceInfo>(2);
contactResources.put(bareId, resources);
}
ResourceInfo oldInfo = null;
for (ResourceInfo ri : resources) {
if (ri.getResourceName().equalsIgnoreCase(resource)) {
oldInfo = ri;
}
}
/* update resource */
if (oldInfo == null) {
oldInfo = new ResourceInfo(resource, presence);
resources.add(oldInfo);
} else {
oldInfo.updateInfo(presence);
}
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.RosterListener#entriesUpdated(java.util.Collection
* )
*/
@Override
public void entriesUpdated(Collection<String> addresses) {
send(addresses, RosterChangeType.MODIFY);
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.RosterListener#entriesDeleted(java.util.Collection
* )
*/
@Override
public void entriesDeleted(Collection<String> addresses) {
send(addresses, RosterChangeType.DELETE);
}
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.RosterListener#entriesAdded(java.util.Collection)
*/
@Override
public void entriesAdded(Collection<String> addresses) {
send(addresses, RosterChangeType.ADD);
}
/**
* Send event bus notification for roster
*
* @param addresses
* @param type
*/
private void send(Collection<String> addresses, RosterChangeType type) {
for (String addy : addresses) {
RosterEntry entry = roster.getEntry(addy);
if (entry != null) {
IRosterChangeEvent event = new RosterChangeEvent(type, entry);
post(event);
}
}
}
/**
* Post event to collaboration event bus
*
* @param event
*/
private void post(Object event) {
CollaborationConnection connection = CollaborationConnection
.getConnection();
connection.postEvent(event);
}
/**
* Get name of resource that supports shared displays for user
*
* @param user
* @return null if no resource found for user that supports shared displays
*/
public String getSharedDisplayEnabledResource(UserId user) {
String rval = null;
synchronized (contactResources) {
List<ResourceInfo> list = contactResources.get(user
.getNormalizedId());
if (list != null) {
for (ResourceInfo ri : list) {
if (ri.supportsSharedDisplays()) {
rval = ri.getResourceName();
break;
}
}
}
}
return rval;
}
}

View file

@ -31,7 +31,6 @@ import org.apache.commons.lang.StringUtils;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;
@ -48,11 +47,8 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.common.util.collections.UpdatingSet;
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.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
/**
* Manage contacts from local groups and roster on server
@ -77,6 +73,8 @@ import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
* Feb 3, 2014 2699 bclement fixed assumption that username search was exact
* Apr 11, 2014 2903 bclement moved roster listener from collaboration connection to here
* Apr 16, 2014 2981 bclement fixed NPE when cached shared group deleted on server
* Apr 23, 2014 2822 bclement moved roster listener to ContactsListener,
* added getSharedDisplayEnabledResource()
*
* </pre>
*
@ -96,6 +94,8 @@ public class ContactsManager {
private Map<String, String> localAliases;
private final ContactsListener contactsListener;
/**
* Cached view of shared groups list on openfire. Will only reach out to
* server if it hasn't updated in an hour. This will disable itself if there
@ -133,59 +133,9 @@ public class ContactsManager {
this.search = connection.createSearch();
localAliases = UserIdWrapper.readAliasMap();
this.xmpp = xmpp;
final Roster roster = xmpp.getRoster();
roster.addRosterListener(new RosterListener() {
@Override
public void presenceChanged(Presence presence) {
String fromId = presence.getFrom();
UserId u = IDConverter.convertFrom(fromId);
if (u != null) {
RosterEntry entry = getRosterEntry(u);
post(entry);
IRosterChangeEvent event = new RosterChangeEvent(
RosterChangeType.PRESENCE, entry, presence);
post(event);
}
}
@Override
public void entriesUpdated(Collection<String> addresses) {
send(addresses, RosterChangeType.MODIFY);
}
@Override
public void entriesDeleted(Collection<String> addresses) {
send(addresses, RosterChangeType.DELETE);
}
@Override
public void entriesAdded(Collection<String> addresses) {
send(addresses, RosterChangeType.ADD);
}
/**
* Send event bus notification for roster
*
* @param addresses
* @param type
*/
private void send(Collection<String> addresses,
RosterChangeType type) {
for (String addy : addresses) {
RosterEntry entry = roster.getEntry(addy);
if (entry != null) {
IRosterChangeEvent event = new RosterChangeEvent(type,
entry);
post(event);
}
}
}
private void post(Object event) {
ContactsManager.this.connection.postEvent(event);
}
});
Roster roster = xmpp.getRoster();
this.contactsListener = new ContactsListener(this, roster);
roster.addRosterListener(this.contactsListener);
}
/**
@ -747,6 +697,15 @@ public class ContactsManager {
return rval;
}
/**
* @see ContactsListener#getSharedDisplayEnabledResource(UserId)
* @param user
* @return
*/
public String getSharedDisplayEnabledResource(UserId user) {
return contactsListener.getSharedDisplayEnabledResource(user);
}
/**
* Listener interface for group update events
*/

View file

@ -0,0 +1,136 @@
/**
* 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.user;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Mode;
import org.jivesoftware.smack.packet.Presence.Type;
/**
* Information for an XMPP resource (client ie pidgin)
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 22, 2014 2822 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ResourceInfo {
public static final String VERSION_KEY = "urn:uf:viz:collaboration:version";
private final String resourceName;
private String collaborationVersion;
private Type lastType;
private Mode lastMode;
/**
* @param resourceName
* @param presence
*/
public ResourceInfo(String resourceName, Presence presence) {
this.resourceName = resourceName;
updateInfo(presence);
}
/**
* Update resource information from presence
*
* @param presence
*/
public void updateInfo(Presence presence) {
Object version = presence.getProperty(VERSION_KEY);
if (version != null) {
this.collaborationVersion = version.toString();
}
this.lastType = presence.getType();
this.lastMode = presence.getMode();
}
/**
* @return true if this resource supports shared displays
*/
public boolean supportsSharedDisplays() {
return this.collaborationVersion != null;
}
/**
* @return the resourceName
*/
public String getResourceName() {
return resourceName;
}
/**
* @return the collaborationVersion
*/
public String getCollaborationVersion() {
return collaborationVersion;
}
/**
* @param collaborationVersion
* the collaborationVersion to set
*/
public void setCollaborationVersion(String collaborationVersion) {
this.collaborationVersion = collaborationVersion;
}
/**
* @return the lastType
*/
public Type getLastType() {
return lastType;
}
/**
* @param lastType
* the lastType to set
*/
public void setLastType(Type lastType) {
this.lastType = lastType;
}
/**
* @return the lastMode
*/
public Mode getLastMode() {
return lastMode;
}
/**
* @param lastMode
* the lastMode to set
*/
public void setLastMode(Mode lastMode) {
this.lastMode = lastMode;
}
}

View file

@ -54,6 +54,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.info.SiteConfigInformatio
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnection;
import com.raytheon.uf.viz.collaboration.comm.provider.connection.CollaborationConnectionData;
import com.raytheon.uf.viz.collaboration.comm.provider.user.ResourceInfo;
import com.raytheon.uf.viz.collaboration.ui.Activator;
import com.raytheon.uf.viz.collaboration.ui.CollaborationUtils;
import com.raytheon.uf.viz.collaboration.ui.ConnectionSubscriber;
@ -77,6 +78,7 @@ import com.raytheon.uf.viz.collaboration.ui.prefs.CollabPrefConstants;
* Apr 07, 2014 2785 mpduff Implemented change to CollaborationConnection
* Apr 11, 2014 2903 bclement added success flag, moved login logic to static method
* fixed populating server with previous, removed password from heap
* Apr 23, 2014 2822 bclement added version to initial presence
*
* </pre>
*
@ -427,7 +429,8 @@ public class LoginDialog extends Dialog {
Presence initialPresence = new Presence(Type.available,
loginData.getMessage(), 0, mode);
Tools.setProperties(initialPresence, loginData.getAttributes());
initialPresence.setProperty(ResourceInfo.VERSION_KEY,
CollaborationConnection.getCollaborationVersion());
collabConnection.getAccountManager().sendPresence(initialPresence);
} catch (CollaborationException e) {