Issue #2822 only allow transfer leader if participant is using shared display
Former-commit-id: af9577548e40397c67f72eb60485ee8de48f169b
This commit is contained in:
parent
8ab1bab974
commit
5250f7a442
5 changed files with 162 additions and 8 deletions
|
@ -36,6 +36,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
|
||||||
* Feb 13, 2014 2751 bclement changed sendObjectToPeer id to VenueParticipant
|
* Feb 13, 2014 2751 bclement changed sendObjectToPeer id to VenueParticipant
|
||||||
* Feb 13, 2014 2751 njensen Added changeLeader()
|
* Feb 13, 2014 2751 njensen Added changeLeader()
|
||||||
* Feb 19, 2014 2751 bclement Added isClosed()
|
* Feb 19, 2014 2751 bclement Added isClosed()
|
||||||
|
* Apr 15, 2014 2822 bclement added isSharedDisplayClient()
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -124,4 +125,10 @@ public interface ISharedDisplaySession extends IVenueSession {
|
||||||
*/
|
*/
|
||||||
public boolean isClosed();
|
public boolean isClosed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param participant
|
||||||
|
* @return true if the participant is viewing the shared display
|
||||||
|
*/
|
||||||
|
public boolean isSharedDisplayClient(VenueParticipant participant);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,10 @@ import org.jivesoftware.smack.packet.Presence;
|
||||||
import org.jivesoftware.smack.packet.XMPPError;
|
import org.jivesoftware.smack.packet.XMPPError;
|
||||||
import org.jivesoftware.smack.provider.ProviderManager;
|
import org.jivesoftware.smack.provider.ProviderManager;
|
||||||
import org.jivesoftware.smackx.muc.MultiUserChat;
|
import org.jivesoftware.smackx.muc.MultiUserChat;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubElementType;
|
||||||
|
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
|
||||||
|
import org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider;
|
||||||
|
import org.jivesoftware.smackx.pubsub.provider.SubscriptionsProvider;
|
||||||
|
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
import com.google.common.net.HostAndPort;
|
import com.google.common.net.HostAndPort;
|
||||||
|
@ -108,6 +112,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
|
||||||
* Apr 09, 2014 2785 mpduff Throw error when not connected and the connection should exist.
|
* Apr 09, 2014 2785 mpduff Throw error when not connected and the connection should exist.
|
||||||
* Apr 14, 2014 2903 bclement moved from session subpackage to connection, removed password from memory,
|
* 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
|
* moved listeners to own classes, reworked connect/register listeners/login order
|
||||||
|
* Apr 15, 2014 2822 bclement added pubsub owner subscriptions provider registration
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -124,6 +129,19 @@ public class CollaborationConnection implements IEventPublisher {
|
||||||
PacketConstants.COLLAB_XMLNS, new SessionPayloadProvider());
|
PacketConstants.COLLAB_XMLNS, new SessionPayloadProvider());
|
||||||
pm.addIQProvider(PacketConstants.QUERY_ELEMENT_NAME,
|
pm.addIQProvider(PacketConstants.QUERY_ELEMENT_NAME,
|
||||||
AuthInfo.AUTH_QUERY_XMLNS, new AuthInfoProvider());
|
AuthInfo.AUTH_QUERY_XMLNS, new AuthInfoProvider());
|
||||||
|
/*
|
||||||
|
* smack doesn't support some of the OWNER operations such as getting
|
||||||
|
* all subscriptions on a node. PubSubOperations creates the request
|
||||||
|
* objects for these operations, but the response needs to be parsed.
|
||||||
|
* Here we register the existing smack parsers using the OWNER
|
||||||
|
* namespace.
|
||||||
|
*/
|
||||||
|
pm.addExtensionProvider(
|
||||||
|
PubSubElementType.SUBSCRIPTION.getElementName(),
|
||||||
|
PubSubNamespace.OWNER.getXmlns(), new SubscriptionProvider());
|
||||||
|
pm.addExtensionProvider(
|
||||||
|
PubSubElementType.SUBSCRIPTIONS.getElementName(),
|
||||||
|
PubSubNamespace.OWNER.getXmlns(), new SubscriptionsProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||||
|
|
|
@ -19,9 +19,18 @@
|
||||||
**/
|
**/
|
||||||
package com.raytheon.uf.viz.collaboration.comm.provider.session;
|
package com.raytheon.uf.viz.collaboration.comm.provider.session;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.packet.IQ.Type;
|
||||||
|
import org.jivesoftware.smack.packet.Packet;
|
||||||
|
import org.jivesoftware.smackx.pubsub.Node;
|
||||||
|
import org.jivesoftware.smackx.pubsub.NodeExtension;
|
||||||
|
import org.jivesoftware.smackx.pubsub.PubSubElementType;
|
||||||
|
import org.jivesoftware.smackx.pubsub.Subscription;
|
||||||
|
import org.jivesoftware.smackx.pubsub.SubscriptionsExtension;
|
||||||
import org.jivesoftware.smackx.pubsub.packet.PubSub;
|
import org.jivesoftware.smackx.pubsub.packet.PubSub;
|
||||||
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
|
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
|
||||||
import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
|
import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
|
||||||
|
@ -38,7 +47,8 @@ import com.raytheon.uf.common.xmpp.ext.ChangeAffiliationExtension;
|
||||||
*
|
*
|
||||||
* Date Ticket# Engineer Description
|
* Date Ticket# Engineer Description
|
||||||
* ------------ ---------- ----------- --------------------------
|
* ------------ ---------- ----------- --------------------------
|
||||||
* Feb 18, 2014 2751 bclement Initial creation
|
* Feb 18, 2014 2751 bclement Initial creation
|
||||||
|
* Apr 15, 2014 2822 bclement added getAllSubscriptions()
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -47,11 +57,14 @@ import com.raytheon.uf.common.xmpp.ext.ChangeAffiliationExtension;
|
||||||
*/
|
*/
|
||||||
public class PubSubOperations {
|
public class PubSubOperations {
|
||||||
|
|
||||||
|
public static final String PUBSUB_SUBDOMAIN_PREFIX = "pubsub.";
|
||||||
|
|
||||||
private PubSubOperations() {
|
private PubSubOperations() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send packet to change affiliation of user on a pubsub topic node
|
* Send packet to change affiliation of user on a pubsub topic node. Calling
|
||||||
|
* client must be owner of node.
|
||||||
*
|
*
|
||||||
* @param conn
|
* @param conn
|
||||||
* @param affiliation
|
* @param affiliation
|
||||||
|
@ -59,12 +72,56 @@ public class PubSubOperations {
|
||||||
*/
|
*/
|
||||||
public static void sendAffiliationPacket(XMPPConnection conn,
|
public static void sendAffiliationPacket(XMPPConnection conn,
|
||||||
ChangeAffiliationExtension affiliation) throws XMPPException {
|
ChangeAffiliationExtension affiliation) throws XMPPException {
|
||||||
PubSub packet = new PubSub();
|
PubSub packet = createOwnerPacket(conn, affiliation, IQ.Type.SET);
|
||||||
packet.setType(IQ.Type.SET);
|
|
||||||
packet.setTo("pubsub." + conn.getServiceName());
|
|
||||||
packet.setPubSubNamespace(PubSubNamespace.OWNER);
|
|
||||||
packet.addExtension(affiliation);
|
|
||||||
SyncPacketSend.getReply(conn, packet);
|
SyncPacketSend.getReply(conn, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all subscriptions on node. Calling client must be owner of node.
|
||||||
|
*
|
||||||
|
* @param conn
|
||||||
|
* @param n
|
||||||
|
* @return
|
||||||
|
* @throws XMPPException
|
||||||
|
*/
|
||||||
|
public static List<Subscription> getAllSubscriptions(XMPPConnection conn,
|
||||||
|
Node n) throws XMPPException {
|
||||||
|
PubSubElementType type = PubSubElementType.SUBSCRIPTIONS;
|
||||||
|
/*
|
||||||
|
* we need to use the OWNER namespace when we make the request, but we
|
||||||
|
* reuse the provider (parser) for the default namespace for the return.
|
||||||
|
* Use the default namespace to get the extension object from the packet
|
||||||
|
*/
|
||||||
|
String namespace = type.getNamespace().getXmlns();
|
||||||
|
NodeExtension ext = new NodeExtension(type, n.getId());
|
||||||
|
PubSub packet = createOwnerPacket(conn, ext, Type.GET);
|
||||||
|
Packet reply = SyncPacketSend.getReply(conn, packet);
|
||||||
|
SubscriptionsExtension resp = (SubscriptionsExtension) reply
|
||||||
|
.getExtension(type.getElementName(), namespace);
|
||||||
|
if (resp == null){
|
||||||
|
throw new XMPPException(
|
||||||
|
"Subscriptions response missing content for topic: "
|
||||||
|
+ n.getId());
|
||||||
|
}
|
||||||
|
return resp.getSubscriptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create pubsub packet object with owner namespace
|
||||||
|
*
|
||||||
|
* @param conn
|
||||||
|
* @param ext
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static PubSub createOwnerPacket(XMPPConnection conn,
|
||||||
|
NodeExtension ext, Type type) {
|
||||||
|
PubSub packet = new PubSub();
|
||||||
|
packet.setType(type);
|
||||||
|
packet.setTo(PUBSUB_SUBDOMAIN_PREFIX + conn.getServiceName());
|
||||||
|
packet.setPubSubNamespace(PubSubNamespace.OWNER);
|
||||||
|
packet.addExtension(ext);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,9 @@ import java.net.URI;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.apache.http.client.methods.HttpDelete;
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
@ -67,6 +69,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.CollaborationConnection;
|
||||||
import com.raytheon.uf.viz.collaboration.comm.provider.connection.PeerToPeerCommHelper;
|
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.event.LeaderChangeEvent;
|
||||||
|
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.UserId;
|
||||||
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
|
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
|
||||||
|
|
||||||
|
@ -95,6 +98,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
|
||||||
* Mar 07, 2014 2848 bclement moved pubsub close logic to closePubSub()
|
* Mar 07, 2014 2848 bclement moved pubsub close logic to closePubSub()
|
||||||
* ensure that subscription is setup before joining room
|
* ensure that subscription is setup before joining room
|
||||||
* Mar 31, 2014 2899 mpduff Improve error messages.
|
* Mar 31, 2014 2899 mpduff Improve error messages.
|
||||||
|
* Apr 15, 2014 2822 bclement added check for other participants being subscribed to topic
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -116,6 +120,8 @@ public class SharedDisplaySession extends VenueSession implements
|
||||||
|
|
||||||
private LeafNode topic;
|
private LeafNode topic;
|
||||||
|
|
||||||
|
private final Map<UserId, Boolean> topicSubscribers = new ConcurrentHashMap<UserId, Boolean>();
|
||||||
|
|
||||||
private XMPPConnection conn;
|
private XMPPConnection conn;
|
||||||
|
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
|
@ -624,6 +630,36 @@ public class SharedDisplaySession extends VenueSession implements
|
||||||
PubSubOperations.sendAffiliationPacket(conn, affiliation);
|
PubSubOperations.sendAffiliationPacket(conn, affiliation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param user
|
||||||
|
* @return true if user has a subscription to the session topic
|
||||||
|
* @throws XMPPException
|
||||||
|
*/
|
||||||
|
private boolean isSubscribedToTopic(UserId user)
|
||||||
|
throws XMPPException {
|
||||||
|
Boolean rval = topicSubscribers.get(user);
|
||||||
|
if (rval == null) {
|
||||||
|
synchronized (topicSubscribers) {
|
||||||
|
List<Subscription> subs = PubSubOperations.getAllSubscriptions(
|
||||||
|
conn, topic);
|
||||||
|
for (Subscription sub : subs) {
|
||||||
|
topicSubscribers.put(IDConverter.convertFrom(sub.getJid()),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rval = topicSubscribers.get(user);
|
||||||
|
if (rval == null) {
|
||||||
|
/*
|
||||||
|
* userid object hash includes resource, cache as a client that
|
||||||
|
* doesn't use topic
|
||||||
|
*/
|
||||||
|
topicSubscribers.put(user, false);
|
||||||
|
rval = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changeLeader(VenueParticipant newLeader)
|
public void changeLeader(VenueParticipant newLeader)
|
||||||
throws CollaborationException {
|
throws CollaborationException {
|
||||||
|
@ -645,6 +681,15 @@ public class SharedDisplaySession extends VenueSession implements
|
||||||
boolean othersNotified = false;
|
boolean othersNotified = false;
|
||||||
String revokeTarget = null;
|
String revokeTarget = null;
|
||||||
try {
|
try {
|
||||||
|
/*
|
||||||
|
* make sure that the new leader is not just in the room, but also
|
||||||
|
* subscribed to the pubsub topic
|
||||||
|
*/
|
||||||
|
if (!isSubscribedToTopic(actualId)) {
|
||||||
|
throw new CollaborationException(
|
||||||
|
"Unable to grant ownership because new leader is not subscribed to session topic");
|
||||||
|
}
|
||||||
|
|
||||||
// was formerly the data provider, so hand off pubsub ownership
|
// was formerly the data provider, so hand off pubsub ownership
|
||||||
grantTopicOwnership(newLeaderId);
|
grantTopicOwnership(newLeaderId);
|
||||||
topicOwnershipGranted = true;
|
topicOwnershipGranted = true;
|
||||||
|
@ -670,6 +715,8 @@ public class SharedDisplaySession extends VenueSession implements
|
||||||
// 'member' instead of just down to 'admin'
|
// 'member' instead of just down to 'admin'
|
||||||
revokeTarget = "room";
|
revokeTarget = "room";
|
||||||
muc.revokeAdmin(account.getNormalizedId());
|
muc.revokeAdmin(account.getNormalizedId());
|
||||||
|
// clear cache of topic subscribers
|
||||||
|
topicSubscribers.clear();
|
||||||
} catch (XMPPException e) {
|
} catch (XMPPException e) {
|
||||||
if (!othersNotified) {
|
if (!othersNotified) {
|
||||||
// transaction, attempt to roll back the ownership changes
|
// transaction, attempt to roll back the ownership changes
|
||||||
|
@ -713,4 +760,27 @@ public class SharedDisplaySession extends VenueSession implements
|
||||||
return closed;
|
return closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession
|
||||||
|
* #isSharedDisplayClient
|
||||||
|
* (com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isSharedDisplayClient(VenueParticipant participant) {
|
||||||
|
UserId actualId = getVenue().getParticipantUserid(participant);
|
||||||
|
boolean rval = false;
|
||||||
|
if (actualId != null) {
|
||||||
|
try {
|
||||||
|
rval = isSubscribedToTopic(actualId);
|
||||||
|
} catch (XMPPException e) {
|
||||||
|
log.error("Error checking if user is a shared display client",
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ import com.raytheon.viz.ui.input.EditableManager;
|
||||||
* Mar 06, 2014 2848 bclement moved colormanager update code to session container
|
* Mar 06, 2014 2848 bclement moved colormanager update code to session container
|
||||||
* Mar 11, 2014 2865 lvenable Added null checks in threads
|
* Mar 11, 2014 2865 lvenable Added null checks in threads
|
||||||
* Mar 18, 2014 2895 njensen Fix lockAction enable/disable logic
|
* Mar 18, 2014 2895 njensen Fix lockAction enable/disable logic
|
||||||
|
* Apr 15, 2014 2822 bclement only allow transfer leader if participant is using shared display
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -539,7 +540,8 @@ public class CollaborationSessionView extends SessionView implements
|
||||||
.getSelection();
|
.getSelection();
|
||||||
VenueParticipant entry = (VenueParticipant) selection
|
VenueParticipant entry = (VenueParticipant) selection
|
||||||
.getFirstElement();
|
.getFirstElement();
|
||||||
if (!entry.isSameUser(session.getUserID())) {
|
if (!entry.isSameUser(session.getUserID())
|
||||||
|
&& session.isSharedDisplayClient(entry)) {
|
||||||
manager.add(leaderChangeAction);
|
manager.add(leaderChangeAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue