diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/META-INF/MANIFEST.MF b/cave/com.raytheon.uf.viz.collaboration.comm/META-INF/MANIFEST.MF index 1753deb5f7..0e3a079873 100644 --- a/cave/com.raytheon.uf.viz.collaboration.comm/META-INF/MANIFEST.MF +++ b/cave/com.raytheon.uf.viz.collaboration.comm/META-INF/MANIFEST.MF @@ -17,7 +17,9 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.swt, com.raytheon.uf.common.comm, com.raytheon.uf.common.localization, - com.raytheon.uf.viz.core + com.raytheon.uf.viz.core, + com.raytheon.uf.common.time, + com.raytheon.uf.common.util Export-Package: com.raytheon.uf.viz.collaboration.comm, com.raytheon.uf.viz.collaboration.comm.compression, com.raytheon.uf.viz.collaboration.comm.identity, diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/CollaborationConnection.java b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/CollaborationConnection.java index e8be6cc269..cb995fcbc3 100644 --- a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/CollaborationConnection.java +++ b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/CollaborationConnection.java @@ -110,6 +110,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueId; * Jan 07, 2013 2563 bclement use getServiceName instead of getHost when creating room id * Jan 08, 2014 2563 bclement fixed custom port and service name in user id * Jan 15, 2014 2630 bclement connection data stores status as Mode object + * Jan 24, 2014 2701 bclement removed roster manager * * * @@ -143,8 +144,6 @@ public class CollaborationConnection implements IEventPublisher { private IAccountManager accountManager = null; - private RosterManager rosterManager = null; - private EventBus eventBus; private ContactsManager contactsMgr; @@ -209,7 +208,7 @@ public class CollaborationConnection implements IEventPublisher { accountManager.sendPresence(initialPresence); } - contactsMgr = new ContactsManager(this); + contactsMgr = new ContactsManager(this, connection); this.registerEventHandler(contactsMgr); instanceMap.put(connectionData, this); @@ -307,28 +306,6 @@ public class CollaborationConnection implements IEventPublisher { return accountManager; } - /** - * - */ - private void setupRosterManager() { - if (rosterManager == null) { - if (isConnected()) { - rosterManager = new RosterManager(connection); - } - } - } - - /** - * - * @return - */ - public RosterManager getRosterManager() { - if (rosterManager == null) { - setupRosterManager(); - } - return rosterManager; - } - /** * Is this SessionManager currently connected? * diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/RosterManager.java b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/RosterManager.java deleted file mode 100644 index b6c1696fac..0000000000 --- a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/RosterManager.java +++ /dev/null @@ -1,100 +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.comm.provider.session; - -import org.jivesoftware.smack.Roster; -import org.jivesoftware.smack.RosterEntry; -import org.jivesoftware.smack.RosterListener; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; - -import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException; - -/** - * Manages roster from server - * - *
- * 
- * SOFTWARE HISTORY
- * 
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Nov 25, 2013 2561       bclement     Initial creation
- * Dec 20, 2013 2563       bclement     added remove from roster method
- * 
- * 
- * - * @author bclement - * @version 1.0 - */ -public class RosterManager { - - private final XMPPConnection connection; - - /** - * @param connection - */ - public RosterManager(XMPPConnection connection) { - this.connection = connection; - } - - /** - * @return roster from server connection - */ - public Roster getRoster() { - return connection.getRoster(); - } - - /** - * Add listener for roster events - * - * @param listener - */ - public void addRosterListener(RosterListener listener) { - getRoster().addRosterListener(listener); - } - - /** - * Remove listener for roster events - * - * @param listener - */ - public void removeRosterListener(RosterListener listener) { - getRoster().removeRosterListener(listener); - } - - /** - * Remove entry from roster on server - * - * @param entry - * @throws CollaborationException - */ - public void removeFromRoster(RosterEntry entry) - throws CollaborationException { - Roster roster = getRoster(); - try { - roster.removeEntry(entry); - } catch (XMPPException e) { - throw new CollaborationException( - "Problem removing user from roster on server", e); - } - } - -} diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/ContactsManager.java b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/ContactsManager.java index 43d706fca3..4e1a827146 100644 --- a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/ContactsManager.java +++ b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/ContactsManager.java @@ -19,41 +19,34 @@ **/ package com.raytheon.uf.viz.collaboration.comm.provider.user; -import java.io.File; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import javax.xml.bind.JAXB; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.jobs.Job; +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.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Presence; -import org.jivesoftware.smack.packet.Presence.Type; +import org.jivesoftware.smack.packet.XMPPError; +import org.jivesoftware.smackx.SharedGroupManager; -import com.raytheon.uf.common.localization.IPathManager; -import com.raytheon.uf.common.localization.LocalizationContext; -import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel; -import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType; -import com.raytheon.uf.common.localization.LocalizationFile; -import com.raytheon.uf.common.localization.PathManagerFactory; import com.raytheon.uf.common.localization.exception.LocalizationOpFailedException; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; 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.provider.Tools; import com.raytheon.uf.viz.collaboration.comm.provider.event.UserNicknameChangedEvent; import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection; -import com.raytheon.uf.viz.collaboration.comm.provider.session.RosterManager; -import com.raytheon.uf.viz.collaboration.comm.provider.user.LocalGroups.LocalGroup; /** * Manage contacts from local groups and roster on server @@ -68,6 +61,9 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.LocalGroups.LocalGro * Dec 6, 2013 2561 bclement removed ECF * Dec 20, 2013 2563 bclement roster items now removed from server, * removed unneeded roster listener + * Jan 24, 2014 2701 bclement removed roster manager + * switched local groups to roster groups + * added shared groups * * * @@ -79,230 +75,320 @@ public class ContactsManager { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(ContactsManager.class); - private final Job storeLocalGroupsJob = new Job("Storing Local Groups") { - - @Override - protected IStatus run(IProgressMonitor monitor) { - IPathManager pm = PathManagerFactory.getPathManager(); - LocalizationContext context = pm.getContext( - LocalizationType.CAVE_STATIC, LocalizationLevel.USER); - LocalizationFile file = PathManagerFactory.getPathManager() - .getLocalizationFile( - context, - "collaboration" + File.separator - + "localGroups.xml"); - LocalGroups obj; - synchronized (localGroups) { - obj = new LocalGroups(localGroups); - } - JAXB.marshal(obj, file.getFile()); - try { - file.save(); - } catch (LocalizationOpFailedException e) { - statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), - e); - } - return org.eclipse.core.runtime.Status.OK_STATUS; - } - }; - private final CollaborationConnection connection; + + private final XMPPConnection xmpp; private final UserSearch search; - private List localGroups; - private Map localAliases; + + /** + * 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 + * is a problem communicating with the server since the most likely case is + * that the server doesn't support the operation. + */ + private UpdatingSet sharedGroups = new UpdatingSet( + TimeUtil.MILLIS_PER_HOUR) { + @Override + protected Set update() { + Set rval; + try { + List names = SharedGroupManager.getSharedGroups(xmpp); + rval = new HashSet(names); + } catch (XMPPException e) { + statusHandler.warn("Unable to get shared groups." + + " Feature may not exist on server", + e.getLocalizedMessage()); + disable(); + rval = null; + } + return rval; + } + }; - private Set groupListeners = new HashSet(); + private Set groupListeners = new HashSet(); - public ContactsManager(CollaborationConnection connection) { + /** + * @param connection + * @param xmpp + */ + public ContactsManager(CollaborationConnection connection, + XMPPConnection xmpp) { this.connection = connection; this.search = connection.createSearch(); localAliases = UserIdWrapper.readAliasMap(); - initLocalGroups(); + this.xmpp = xmpp; + } + + /** + * Get groups that are managed by server. These are not modifiable from the + * client. + * + * @return + */ + public Collection getSharedGroups() { + Set groups = sharedGroups.get(); + List rval = new ArrayList(groups.size()); + Roster roster = getRoster(); + for (String group : groups) { + RosterGroup rg = roster.getGroup(group); + rval.add(new SharedGroup(rg)); + } + return rval; } - private void initLocalGroups() { - storeLocalGroupsJob.setSystem(true); - IPathManager pm = PathManagerFactory.getPathManager(); - LocalizationContext context = pm.getContext( - LocalizationType.CAVE_STATIC, LocalizationLevel.USER); - LocalizationFile file = PathManagerFactory.getPathManager() - .getLocalizationFile(context, - "collaboration" + File.separator + "localGroups.xml"); - if (file.exists()) { - this.localGroups = JAXB - .unmarshal(file.getFile(), LocalGroups.class).getGroups(); - } - - if (this.localGroups == null) { - this.localGroups = new ArrayList(); - } - for (LocalGroup group : localGroups) { - group.setManager(this); - } - } - - public List getLocalGroups() { - synchronized (this.localGroups) { - return new ArrayList(this.localGroups); - } - } - - public void addToLocalGroup(String groupName, UserId user) { - synchronized (this.localGroups) { - LocalGroup group = createLocalGroup(groupName); - String userId = user.getNormalizedId(); - List userNames = group.getUserNames(); - if (!userNames.contains(userId)) { - List users = group.getUsers(); - group.getUserNames().add(userId); - users.add(user); - } - RosterEntry entry = getRosterEntry(user); - if (entry == null || entry.getGroups().isEmpty()) { - // In order to get presence for a user they must be in the - // roster, we can add them to the roster by either subscribing - // to them using presence or adding them to the roster, - // subscribing to the presence will not set the name correctly - // so we use the roster add method. - try { - RosterManager rosterManager = connection.getRosterManager(); - Roster roster = rosterManager.getRoster(); - roster.createEntry(userId, user.getAlias(), new String[0]); - } catch (XMPPException e) { - statusHandler.handle(Priority.PROBLEM, - e.getLocalizedMessage(), e); + /** + * Get groups that are managed by the client. This does not included shared + * groups. + * + * @return + */ + public Collection getGroups() { + Set shared = sharedGroups.get(); + Collection groups = getRoster().getGroups(); + Collection rval; + if (shared.isEmpty()) { + rval = groups; + } else { + rval = new ArrayList(groups.size()); + for (RosterGroup group : groups) { + if (!shared.contains(group.getName())) { + rval.add(group); } } - for (LocalGroupListener listener : getSafeGroupListeners()) { + } + return rval; + } + + /** + * Add user to group. Creates group if it doesn't exist. Adds user to + * contacts if not in roster. + * + * @param groupName + * @param user + */ + public void addToGroup(String groupName, UserId user) { + Roster roster = getRoster(); + RosterGroup group = roster.getGroup(groupName); + if (group == null) { + group = createGroup(groupName); + } + String id = user.getNormalizedId(); + RosterEntry entry = group.getEntry(id); + if (entry != null) { + statusHandler + .debug("Attempted to add user to group it was already in: " + + id + " in " + groupName); + return; + } + try { + addToGroup(group, user); + for (GroupListener listener : getSafeGroupListeners()) { listener.userAdded(group, user); } + } catch (XMPPException e) { + String msg = getGroupModInfo(e); + statusHandler.error("Problem adding user to group: " + id + " to " + + group.getName() + ". " + msg, e); } - storeLocalGroupsJob.schedule(); } - public void deleteFromLocalGroup(String groupName, UserId user) { - synchronized (localGroups) { - Iterator it = localGroups.iterator(); - while (it.hasNext()) { - LocalGroup group = it.next(); - if (group.getName().equals(groupName)) { - group.getUsers().remove(user); - group.getUserNames().remove(user.getNormalizedId()); - for (LocalGroupListener listener : getSafeGroupListeners()) { - listener.userDeleted(group, user); - } - break; - } + /** + * Add user to group. Adds user to contacts if not in roster. + * + * @param group + * @param user + * @throws XMPPException + */ + private void addToGroup(RosterGroup group, UserId user) + throws XMPPException { + RosterEntry entry = getRosterEntry(user); + if (entry == null) { + // we dont have user as a contact at all + // ensure that the user object is up-to-date + user = findUser(user.getName()); + String alias = user.getAlias(); + if (StringUtils.isBlank(alias)) { + alias = user.getName(); } - if (getLocalGroups(user).isEmpty()) { - // if the user is in no local groups and no roster groups remove - // them from our roster. - RosterEntry entry = getRosterEntry(user); - if (entry != null && entry.getGroups().isEmpty()) { - Presence presence = new Presence(Type.unsubscribe); - presence.setTo(user.getNormalizedId()); - try { - connection.getAccountManager().sendPresence(presence); - } catch (CollaborationException e) { - statusHandler.error( - "Problem removing user from roster", e); - } - removeFromRoster(entry); - } - } - storeLocalGroupsJob.schedule(); + getRoster().createEntry(user.getFQName(), alias, + new String[] { group.getName() }); + } else { + // just need to update groups + group.addEntry(entry); } } + /** + * Remove user from group. + * + * @param groupName + * @param user + */ + public void deleteFromGroup(String groupName, UserId user) { + RosterEntry entry = getRosterEntry(user); + if ( entry == null){ + statusHandler.warn("Attempted to alter group for non-contact: " + user); + return; + } + RosterGroup group = getRoster().getGroup(groupName); + if ( group != null){ + deleteFromGroup(group, entry); + } else { + statusHandler.warn("Attempted to modify non-existent group: " + + groupName); + } + } + + /** + * Remove entry from group. + * + * @param group + * @param entry + */ + private void deleteFromGroup(RosterGroup group, RosterEntry entry) { + try { + group.removeEntry(entry); + for (GroupListener listener : getSafeGroupListeners()) { + listener.userDeleted(group, IDConverter.convertFrom(entry)); + } + } catch (XMPPException e) { + String msg = getGroupModInfo(e); + statusHandler.error("Problem removing entry from group: " + + IDConverter.convertFrom(entry) + " from " + + group.getName() + ". " + msg, e); + } + } + + /** + * Attempt to get more information about group modification error. Returns + * an empty string if no extra information is found. + * + * @param e + * @return + */ + private String getGroupModInfo(XMPPException e) { + XMPPError xmppError = e.getXMPPError(); + String rval = ""; + if (xmppError != null) { + switch (xmppError.getCode()) { + case 406: + rval = "Group may not be modifiable. "; + break; + } + } + return rval; + } + /** * Remove entry from roster on server * * @param entry + * @throws CollaborationException */ public void removeFromRoster(RosterEntry entry) { - RosterManager rosterManager = connection.getRosterManager(); + Roster roster = getRoster(); try { - rosterManager.removeFromRoster(entry); - } catch (CollaborationException e) { + roster.removeEntry(entry); + } catch (XMPPException e) { statusHandler.error("Problem removing roster entry", e); } } - public LocalGroup createLocalGroup(String groupName) { - synchronized (localGroups) { - for (LocalGroup group : this.localGroups) { - if (groupName.equals(group.getName())) { - return group; - } - } - LocalGroup group = new LocalGroup(groupName); - group.setManager(this); - localGroups.add(group); - for (LocalGroupListener listener : getSafeGroupListeners()) { + /** + * Create group. At least one entry must be placed into group for it to be + * persisted on server. + * + * @param groupName + * @return + */ + public RosterGroup createGroup(String groupName) { + Roster roster = getRoster(); + RosterGroup rval = roster.getGroup(groupName); + if ( rval != null){ + statusHandler.debug("Attempted to create existing group: " + groupName); + return rval; + } + rval = roster.createGroup(groupName); + for (GroupListener listener : getSafeGroupListeners()) { + listener.groupCreated(rval); + } + return rval; + } + + /** + * Remove all users from group. + * + * @param groupName + */ + public void deleteGroup(String groupName) { + Roster roster = getRoster(); + RosterGroup group = roster.getGroup(groupName); + if ( group == null){ + statusHandler.warn("Attempted to delete non-existent group: " + + groupName); + return; + } + Collection entries = group.getEntries(); + for (RosterEntry entry : entries) { + deleteFromGroup(group, entry); + } + for (GroupListener listener : getSafeGroupListeners()) { + listener.groupDeleted(group); + } + } + + /** + * Move all users from old group to new group. If new group already exists, + * this will merge the two groups. + * + * @param oldName + * @param newName + */ + public void renameGroup(String oldName, String newName) { + Roster roster = getRoster(); + RosterGroup group = roster.getGroup(oldName); + if (group == null) { + statusHandler.warn("Attempted to rename non-existent group: " + + oldName); + return; + } + boolean merger = roster.getGroup(newName) != null; + group.setName(newName); + for (GroupListener listener : getSafeGroupListeners()) { + listener.groupDeleted(group); + } + if (!merger) { + for (GroupListener listener : getSafeGroupListeners()) { listener.groupCreated(group); } - storeLocalGroupsJob.schedule(); - return group; } } - public void deleteLocalGroup(String groupName) { - synchronized (localGroups) { - Iterator it = this.localGroups.iterator(); - while (it.hasNext()) { - LocalGroup group = it.next(); - if (groupName.equals(group.getName())) { - List users = new ArrayList( - group.getUsers()); - for (UserId user : users) { - deleteFromLocalGroup(groupName, user); - } - it.remove(); - for (LocalGroupListener listener : getSafeGroupListeners()) { - listener.groupDeleted(group); - } - } - } + /** + * Get groups that the user is in. + * + * @param user + * @return + */ + public Collection getGroups(UserId user) { + RosterEntry entry = getRoster().getEntry(user.getNormalizedId()); + if (entry == null) { + statusHandler.error("Requested groups for user not in roster: " + + user); + return Collections.emptyList(); } - storeLocalGroupsJob.schedule(); - } - - public void renameLocalGroup(String oldName, String newName) { - synchronized (localGroups) { - - for (LocalGroup group : localGroups) { - if (oldName.equals(group.getName())) { - for (LocalGroupListener listener : getSafeGroupListeners()) { - listener.groupDeleted(group); - } - group.setName(newName); - for (LocalGroupListener listener : getSafeGroupListeners()) { - listener.groupCreated(group); - } - } - } - } - storeLocalGroupsJob.schedule(); - } - - public List getLocalGroups(UserId user) { - List results = new ArrayList(); - synchronized (localGroups) { - for (LocalGroup group : localGroups) { - for (String userName : group.getUserNames()) { - if (user.getNormalizedId().equals(userName)) { - results.add(group); - break; - } - } - } - } - return results; + return entry.getGroups(); } + /** + * Update local alias for user. Does not persist to server. + * + * @param user + * @param nickname + */ public void setNickname(UserId user, String nickname) { synchronized (localAliases) { @@ -348,18 +434,36 @@ public class ContactsManager { return alias; } + /** + * Get user info from roster. Does not include local alias information. + * + * @param userId + * @return + */ public UserId getUser(String userId) { - RosterEntry entry = searchRoster(getRoster(), userId); + RosterEntry entry = searchRoster(userId); if (entry == null) { return null; } return IDConverter.convertFrom(entry); } + /** + * Get entry from roster for user. Does not include local alias information. + * + * @param user + * @return + */ public RosterEntry getRosterEntry(UserId user) { - return searchRoster(user); + return searchRoster(user.getNormalizedId()); } + /** + * Get last known presence for contact. + * + * @param user + * @return + */ public Presence getPresence(UserId user) { UserId self = connection.getUser(); if (self.isSameUser(user)) { @@ -369,54 +473,35 @@ public class ContactsManager { return roster.getPresence(user.getNormalizedId()); } + /** + * Get presence for this account. + * + * @return + */ public Presence getSelfPresence() { return connection.getPresence(); } /** - * Used by local groups to make sure all local group items are in the - * roster. + * Convenience method for accessing roster. * - * @param name - * @return - */ - protected UserId findAndAddUser(String id) { - UserId user = null; - RosterEntry entry = searchRoster(getRoster(), id); - if (entry != null) { - user = IDConverter.convertFrom(entry); - } - if (user == null) { - user = findUser(id); - if (user != null) { - try { - Roster roster = connection.getRosterManager().getRoster(); - String alias = user.getAlias(); - if (alias == null || alias.trim().isEmpty()) { - alias = user.getName(); - } - roster.createEntry(user.getFQName(), alias, new String[0]); - } catch (XMPPException e) { - statusHandler.handle(Priority.PROBLEM, - e.getLocalizedMessage(), e); - } - } - } - return user; - - } - - /** * @return */ private Roster getRoster() { - return connection.getRosterManager().getRoster(); + return xmpp.getRoster(); } - private UserId findUser(String idString) { + /** + * Perform an XMPP search for user. Includes any local alias information. + * + * @param username + * The part of the userid before the '@' + * @return null if not found + */ + private UserId findUser(String username) { List results; try { - results = search.byId(idString); + results = search.byUsername(username); } catch (XMPPException e) { statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e); return null; @@ -431,44 +516,72 @@ public class ContactsManager { return results.isEmpty() ? null : results.iterator().next(); } - private RosterEntry searchRoster(UserId user) { - String userId = user.getNormalizedId(); - return searchRoster(connection.getRosterManager().getRoster(), userId); + /** + * Get entry from roster for user. Does not include local alias information. + * + * @param userId + * @return + */ + private RosterEntry searchRoster(String userId) { + return getRoster().getEntry(userId); } - private RosterEntry searchRoster(Roster roster, String userId) { - return roster.getEntry(userId); - } - - public void addLocalGroupListener(LocalGroupListener listener) { + /** + * Add listeners to get information on when groups are modified + * + * @param listener + */ + public void addGroupListener(GroupListener listener) { synchronized (groupListeners) { groupListeners.add(listener); } } - public void removeLocalGroupListener(LocalGroupListener listener) { + /** + * Remove listener + * + * @param listener + */ + public void removeGroupListener(GroupListener listener) { synchronized (groupListeners) { groupListeners.remove(listener); } } - protected Set getSafeGroupListeners() { - Set safeSet = new HashSet(); + /** + * Get a copy of the listeners set + * + * @return + */ + protected Set getSafeGroupListeners() { + Set safeSet = new HashSet(); synchronized (groupListeners) { safeSet.addAll(groupListeners); } return safeSet; } - public static interface LocalGroupListener { + /** + * Get a list of roster entries that do not belong to any group + * + * @return + */ + public Collection getNonGroupedContacts() { + return getRoster().getUnfiledEntries(); + } - public void groupCreated(LocalGroup group); + /** + * Listener interface for group update events + */ + public static interface GroupListener { - public void groupDeleted(LocalGroup group); + public void groupCreated(RosterGroup group); - public void userAdded(LocalGroup group, UserId user); + public void groupDeleted(RosterGroup group); - public void userDeleted(LocalGroup group, UserId user); + public void userAdded(RosterGroup group, UserId user); + + public void userDeleted(RosterGroup group, UserId user); } } diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/LocalGroups.java b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/LocalGroups.java deleted file mode 100644 index cae232048d..0000000000 --- a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/LocalGroups.java +++ /dev/null @@ -1,131 +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.comm.provider.user; - -import java.util.ArrayList; -import java.util.List; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlTransient; - -/** - * Group information not stored on chat server - * - *
- * 
- * SOFTWARE HISTORY
- * 
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Jul 2, 2012            bsteffen     Initial creation
- * 
- * 
- * - * @author bsteffen - * @version 1.0 - */ -@XmlAccessorType(XmlAccessType.NONE) -@XmlRootElement(name = "LocalGroups") -public class LocalGroups { - - @XmlElement(name = "group") - private List groups; - - public LocalGroups() { - } - - public LocalGroups(List groups) { - this.groups = new ArrayList(groups); - } - - public List getGroups() { - return groups; - } - - public void setGroups(List groups) { - this.groups = groups; - } - - @XmlAccessorType(XmlAccessType.NONE) - public static class LocalGroup { - - @XmlAttribute - private String name; - - @XmlElement(name = "user") - private List userNames; - - @XmlTransient - private ContactsManager manager; - - @XmlTransient - private List users; - - public LocalGroup() { - } - - public LocalGroup(String name) { - this.name = name; - this.userNames = new ArrayList(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getUserNames() { - if (userNames == null) { - userNames = new ArrayList(); - } - return userNames; - } - - public void setUserNames(List userNames) { - this.userNames = userNames; - } - - public synchronized List getUsers() { - if (users == null) { - users = new ArrayList(); - for (String userName : userNames) { - UserId user = manager.findAndAddUser(userName); - if (user != null) { - users.add(user); - } - } - } - return users; - } - - public void setManager(ContactsManager manager) { - this.manager = manager; - } - - } - -} diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/SharedGroup.java b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/SharedGroup.java new file mode 100644 index 0000000000..18aa5b4e2f --- /dev/null +++ b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/SharedGroup.java @@ -0,0 +1,76 @@ +/** + * 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.Collection; + +import org.jivesoftware.smack.RosterEntry; +import org.jivesoftware.smack.RosterGroup; + +/** + * Shared group managed by xmpp server. Cannot be modified by client. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 23, 2014 2701       bclement    Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class SharedGroup { + + private final RosterGroup delegate; + + /** + * @param group + */ + public SharedGroup(RosterGroup group) { + this.delegate = group; + } + + /** + * @return name of group + */ + public String getName() { + return delegate.getName(); + } + + /** + * @return collection of entries in this group + */ + public Collection getEntries() { + return delegate.getEntries(); + } + + /** + * @param entry + * @return true if entry is in this group + */ + public boolean contains(RosterEntry entry) { + return delegate.contains(entry); + } + +} diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/UserSearch.java b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/UserSearch.java index e903084e6c..655ca9b2b8 100644 --- a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/UserSearch.java +++ b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/UserSearch.java @@ -46,6 +46,7 @@ import com.raytheon.uf.common.status.UFStatus; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Nov 22, 2013 2561 bclement Initial creation + * Jan 24, 2014 2701 bclement distinction between userid and username * * * @@ -62,7 +63,7 @@ public class UserSearch { private static final String SEARCH_ACTION = "search"; - public static final String USERID_FIELD = "Username"; + public static final String USERNAME_FIELD = "Username"; public static final String JABBER_ID_COLUMN = "jid"; @@ -81,14 +82,14 @@ public class UserSearch { } /** - * Search by username + * Search by username (the part of the user id before the @) * * @param name * @return list of user ids that match that name * @throws XMPPException */ - public List byId(String id) throws XMPPException { - return byCriteria(USERID_FIELD, id); + public List byUsername(String username) throws XMPPException { + return byCriteria(USERNAME_FIELD, username); } /** diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/icons/local_group.gif b/cave/com.raytheon.uf.viz.collaboration.ui/icons/roster_group.gif similarity index 100% rename from cave/com.raytheon.uf.viz.collaboration.ui/icons/local_group.gif rename to cave/com.raytheon.uf.viz.collaboration.ui/icons/roster_group.gif diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/icons/group.gif b/cave/com.raytheon.uf.viz.collaboration.ui/icons/shared_group.gif similarity index 100% rename from cave/com.raytheon.uf.viz.collaboration.ui/icons/group.gif rename to cave/com.raytheon.uf.viz.collaboration.ui/icons/shared_group.gif diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/CollaborationGroupView.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/CollaborationGroupView.java index fc8696f223..84526b0e6b 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/CollaborationGroupView.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/CollaborationGroupView.java @@ -21,6 +21,7 @@ package com.raytheon.uf.viz.collaboration.ui; **/ import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -88,9 +89,9 @@ import com.raytheon.uf.viz.collaboration.comm.provider.event.UserNicknameChanged import com.raytheon.uf.viz.collaboration.comm.provider.event.UserPresenceChangedEvent; import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection; import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager; -import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager.LocalGroupListener; +import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager.GroupListener; import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter; -import com.raytheon.uf.viz.collaboration.comm.provider.user.LocalGroups.LocalGroup; +import com.raytheon.uf.viz.collaboration.comm.provider.user.SharedGroup; import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId; import com.raytheon.uf.viz.collaboration.ui.actions.AddToGroupAction; import com.raytheon.uf.viz.collaboration.ui.actions.ArchiveViewerAction; @@ -100,7 +101,6 @@ import com.raytheon.uf.viz.collaboration.ui.actions.ChangeRoleAction; import com.raytheon.uf.viz.collaboration.ui.actions.ChangeSiteAction; import com.raytheon.uf.viz.collaboration.ui.actions.ChangeStatusAction; import com.raytheon.uf.viz.collaboration.ui.actions.ChangeStatusMessageAction; -import com.raytheon.uf.viz.collaboration.ui.actions.CreateGroupAction; import com.raytheon.uf.viz.collaboration.ui.actions.CreateSessionAction; import com.raytheon.uf.viz.collaboration.ui.actions.DeleteGroupAction; import com.raytheon.uf.viz.collaboration.ui.actions.DisplayFeedAction; @@ -136,6 +136,8 @@ import com.raytheon.viz.ui.views.CaveFloatingView; * Dec 6, 2013 2561 bclement removed ECF * Dec 19, 2013 2563 bclement added subscribe method for server disconnection * Dec 20, 2013 2563 bclement fixed support for ungrouped roster items + * Jan 24, 2014 2701 bclement removed local groups, added shared groups + * removed option to create empty group * * * @@ -143,7 +145,7 @@ import com.raytheon.viz.ui.views.CaveFloatingView; * @version 1.0 */ public class CollaborationGroupView extends CaveFloatingView implements - LocalGroupListener, IUserSelector { + GroupListener, IUserSelector { public static final String ID = "com.raytheon.uf.viz.collaboration.ui.CollaborationGroupView"; private TreeViewer usersTreeViewer; @@ -228,7 +230,7 @@ public class CollaborationGroupView extends CaveFloatingView implements if (connection != null) { connection.registerEventHandler(this); } - connection.getContactsManager().addLocalGroupListener(this); + connection.getContactsManager().addGroupListener(this); populateTree(); usersTreeViewer.refresh(); parent.layout(); @@ -240,7 +242,7 @@ public class CollaborationGroupView extends CaveFloatingView implements .getConnection(); if (connection != null) { connection.unregisterEventHandler(this); - connection.getContactsManager().removeLocalGroupListener(this); + connection.getContactsManager().removeGroupListener(this); } super.dispose(); @@ -311,7 +313,6 @@ public class CollaborationGroupView extends CaveFloatingView implements } private void createMenu(IMenuManager mgr) { - mgr.add(new CreateGroupAction()); mgr.add(new UserSearchAction()); mgr.add(new Separator()); mgr.add(new ChangeFontAction()); @@ -402,10 +403,10 @@ public class CollaborationGroupView extends CaveFloatingView implements // the user, both the logged in user as well as entries in groups UserId user = (UserId) o; fillContextMenu(manager, selection, user); - } else if (o instanceof RosterGroup || o instanceof LocalGroup) { + } else if (o instanceof RosterGroup || o instanceof SharedGroup) { manager.add(createSessionAction); - if (o instanceof LocalGroup) { - LocalGroup group = (LocalGroup) o; + if (o instanceof RosterGroup) { + RosterGroup group = (RosterGroup) o; manager.add(new DeleteGroupAction(group.getName())); aliasAction.setId(group.getName()); aliasAction.setText("Rename Group"); @@ -438,8 +439,8 @@ public class CollaborationGroupView extends CaveFloatingView implements manager.add(new AddToGroupAction(getSelectedUsers())); String groupName = null; Object group = selection.getPaths()[0].getFirstSegment(); - if (group instanceof LocalGroup) { - groupName = ((LocalGroup) group).getName(); + if (group instanceof RosterGroup) { + groupName = ((RosterGroup) group).getName(); manager.add(new RemoveFromGroupAction(groupName, getSelectedUsers())); } } @@ -587,14 +588,14 @@ public class CollaborationGroupView extends CaveFloatingView implements CollaborationConnection.getConnection().getContactsManager() .setNickname(user, newText); CollaborationConnection.getConnection().postEvent(user); - for (LocalGroup group : CollaborationConnection.getConnection() - .getContactsManager().getLocalGroups(user)) { + for (RosterGroup group : CollaborationConnection.getConnection() + .getContactsManager().getGroups(user)) { usersTreeViewer.refresh(group); } - } else if (selectedObj instanceof LocalGroup) { - LocalGroup group = (LocalGroup) selectedObj; + } else if (selectedObj instanceof RosterGroup) { + RosterGroup group = (RosterGroup) selectedObj; CollaborationConnection.getConnection().getContactsManager() - .renameLocalGroup(group.getName(), newText); + .renameGroup(group.getName(), newText); } } @@ -790,16 +791,13 @@ public class CollaborationGroupView extends CaveFloatingView implements UserId user = IDConverter.convertFrom((RosterEntry) node); selectedUsers.add(user); } else if (node instanceof RosterGroup) { - selectedUsers.addAll(getSelectedUsers((RosterGroup) node)); - } else if (node instanceof LocalGroup) { - for (UserId user : ((LocalGroup) node).getUsers()) { - Presence presence = CollaborationConnection - .getConnection().getContactsManager() - .getPresence(user); - if (presence.getType() == Presence.Type.available) { - selectedUsers.add(user); - } - } + Collection entries = ((RosterGroup) node) + .getEntries(); + selectedUsers.addAll(getSelectedUsers(entries)); + } else if (node instanceof SharedGroup) { + Collection entries = ((SharedGroup) node) + .getEntries(); + selectedUsers.addAll(getSelectedUsers(entries)); } } @@ -807,17 +805,16 @@ public class CollaborationGroupView extends CaveFloatingView implements } /** - * This recursively searches group Nodes and returns all users with Type - * AVAILABLE. + * This searches group entries and returns all users with Type AVAILABLE. * - * @param groupNode + * @param entries * @return users */ - private Set getSelectedUsers(RosterGroup groupNode) { + private Set getSelectedUsers(Collection entries) { Set selectedUsers = new HashSet(); ContactsManager contacts = CollaborationConnection.getConnection() .getContactsManager(); - for (RosterEntry node : groupNode.getEntries()) { + for (RosterEntry node : entries) { UserId user = IDConverter.convertFrom(node); Presence presence = contacts.getPresence(user); if (presence.getType() == Type.available) { @@ -902,22 +899,22 @@ public class CollaborationGroupView extends CaveFloatingView implements } @Override - public void groupCreated(LocalGroup group) { + public void groupCreated(RosterGroup group) { refreshUsersTreeViewerAsync(usersTreeViewer.getInput()); } @Override - public void groupDeleted(LocalGroup group) { + public void groupDeleted(RosterGroup group) { refreshUsersTreeViewerAsync(usersTreeViewer.getInput()); } @Override - public void userAdded(LocalGroup group, UserId user) { + public void userAdded(RosterGroup group, UserId user) { refreshUsersTreeViewerAsync(group); } @Override - public void userDeleted(LocalGroup group, UserId user) { + public void userDeleted(RosterGroup group, UserId user) { refreshUsersTreeViewerAsync(group); } diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/CreateGroupDialog.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/CreateGroupDialog.java index 96ae44ba3d..9798c0c3bc 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/CreateGroupDialog.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/CreateGroupDialog.java @@ -37,7 +37,8 @@ import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConn import com.raytheon.viz.ui.dialogs.CaveSWTDialog; /** - * TODO Add Description + * Dialog allowing user to create a new group in the roster. At least one user + * must be added to the group afterwards for it to be persisted on the server. * *
  * 
@@ -46,13 +47,13 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Jun 27, 2012            bsteffen     Initial creation
+ * Jan 24, 2014 2701       bclement     removed local groups
  * 
  * 
* * @author bsteffen * @version 1.0 */ - public class CreateGroupDialog extends CaveSWTDialog { private Text nameText; @@ -115,7 +116,7 @@ public class CreateGroupDialog extends CaveSWTDialog { private void finish() { newGroup = nameText.getText(); CollaborationConnection.getConnection().getContactsManager() - .createLocalGroup(newGroup); + .createGroup(newGroup); close(); } diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeContentProvider.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeContentProvider.java index f332528f0a..7ad8dae547 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeContentProvider.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeContentProvider.java @@ -33,13 +33,13 @@ import org.jivesoftware.smack.RosterGroup; import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection; import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter; -import com.raytheon.uf.viz.collaboration.comm.provider.user.LocalGroups.LocalGroup; +import com.raytheon.uf.viz.collaboration.comm.provider.user.SharedGroup; import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId; import com.raytheon.uf.viz.collaboration.ui.data.CollaborationGroupContainer; import com.raytheon.uf.viz.collaboration.ui.data.SessionGroupContainer; /** - * TODO Add Description + * Provides access to contacts list tree * *
  * 
@@ -49,6 +49,7 @@ import com.raytheon.uf.viz.collaboration.ui.data.SessionGroupContainer;
  * ------------ ---------- ----------- --------------------------
  * Mar 1, 2012            rferrel     Initial creation
  * Dec  6, 2013 2561       bclement    removed ECF
+ * Jan 24, 2014 2701       bclement    removed local groups, added shared groups
  * 
  * 
* @@ -118,35 +119,33 @@ public class UsersTreeContentProvider implements ITreeContentProvider { return cont.getObjects().toArray(); } else if (parentElement instanceof RosterGroup) { RosterGroup group = (RosterGroup) parentElement; - List result = new ArrayList(); - UserId localUser = CollaborationConnection.getConnection() - .getUser(); - Collection entries = group.getEntries(); - synchronized (entries) { - entries = new ArrayList(entries); - } - for (RosterEntry entry : entries) { - String user = entry.getUser(); - if (!localUser.isSameUser(user)) { - result.add(IDConverter.convertFrom(entry)); - } - } - return result.toArray(); - } else if (parentElement instanceof LocalGroup) { - List result = new ArrayList(); - LocalGroup group = (LocalGroup) parentElement; - UserId localUser = CollaborationConnection.getConnection() - .getUser(); - for (UserId user : group.getUsers()) { - if (!localUser.isSameUser(user.getNormalizedId())) { - result.add(user); - } - } - return result.toArray(); + return getRosterChildren(group.getEntries()); + } else if (parentElement instanceof SharedGroup) { + SharedGroup group = (SharedGroup) parentElement; + return getRosterChildren(group.getEntries()); } return null; } + /** + * Get child objects of roster groups + * + * @param entries + * entries in group + * @return + */ + private Object[] getRosterChildren(Collection entries) { + List result = new ArrayList(); + UserId localUser = CollaborationConnection.getConnection().getUser(); + for (RosterEntry entry : entries) { + String user = entry.getUser(); + if (!localUser.isSameUser(user)) { + result.add(IDConverter.convertFrom(entry)); + } + } + return result.toArray(); + } + /* * (non-Javadoc) * @@ -172,19 +171,10 @@ public class UsersTreeContentProvider implements ITreeContentProvider { boolean hasChildren = false; if (element instanceof RosterGroup) { RosterGroup group = (RosterGroup) element; - UserId localUser = CollaborationConnection.getConnection() - .getUser(); - Collection entries = group.getEntries(); - synchronized (entries) { - entries = new ArrayList(entries); - } - for (RosterEntry entry : entries) { - String user = entry.getUser(); - if (!localUser.isSameUser(user)) { - hasChildren = true; - break; - } - } + hasChildren = rosterHasChildren(group.getEntries()); + } else if (element instanceof SharedGroup) { + SharedGroup group = (SharedGroup) element; + hasChildren = rosterHasChildren(group.getEntries()); } else if (element instanceof SessionGroupContainer) { SessionGroupContainer cont = (SessionGroupContainer) element; if (cont.getObjects() != null && cont.getObjects().size() > 0) { @@ -192,16 +182,6 @@ public class UsersTreeContentProvider implements ITreeContentProvider { } else { hasChildren = false; } - } else if (element instanceof LocalGroup) { - UserId localUser = CollaborationConnection.getConnection() - .getUser(); - List userNames = ((LocalGroup) element).getUserNames(); - for (String userName : userNames) { - if (!localUser.isSameUser(userName)) { - hasChildren = true; - break; - } - } } // need to check whether items are filtered out so we don't get @@ -219,4 +199,22 @@ public class UsersTreeContentProvider implements ITreeContentProvider { } return hasChildren; } + + /** + * @param entries + * @return true if entries has at least one entry that isn't the users + * account + */ + private boolean rosterHasChildren(Collection entries) { + UserId localUser = CollaborationConnection.getConnection().getUser(); + boolean hasChildren = false; + for (RosterEntry entry : entries) { + String user = entry.getUser(); + if (!localUser.isSameUser(user)) { + hasChildren = true; + break; + } + } + return hasChildren; + } } diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeLabelProvider.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeLabelProvider.java index 3397c1c87c..a7e9c0df3c 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeLabelProvider.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeLabelProvider.java @@ -43,7 +43,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession; import com.raytheon.uf.viz.collaboration.comm.identity.info.IVenueInfo; import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection; import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter; -import com.raytheon.uf.viz.collaboration.comm.provider.user.LocalGroups.LocalGroup; +import com.raytheon.uf.viz.collaboration.comm.provider.user.SharedGroup; import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId; import com.raytheon.uf.viz.collaboration.ui.data.SessionGroupContainer; @@ -59,6 +59,7 @@ import com.raytheon.uf.viz.collaboration.ui.data.SessionGroupContainer; * Mar 1, 2012 rferrel Initial creation * Dec 6, 2013 2561 bclement removed ECF * Dec 20, 2013 2563 bclement fixed support for ungrouped roster items + * Jan 24, 2014 2701 bclement removed local groups, added shared groups * * * @@ -105,13 +106,13 @@ public class UsersTreeLabelProvider extends ColumnLabelProvider { return userLabelProvider.getImage(IDConverter .convertFrom((RosterEntry) element)); } else if (element instanceof RosterGroup) { - key = "group"; + key = "roster_group"; + } else if (element instanceof SharedGroup) { + key = "shared_group"; } else if (element instanceof IVenueSession) { // key = "session_group"; } else if (element instanceof SessionGroupContainer) { key = "session_group"; - } else if (element instanceof LocalGroup) { - key = "local_group"; } if (imageMap.get(key) == null && !key.equals("")) { @@ -124,6 +125,8 @@ public class UsersTreeLabelProvider extends ColumnLabelProvider { public String getText(Object element) { if (element instanceof RosterGroup) { return ((RosterGroup) element).getName(); + } else if (element instanceof SharedGroup) { + return ((SharedGroup) element).getName(); } else if (element instanceof RosterEntry) { return userLabelProvider.getText(IDConverter .convertFrom((RosterEntry) element)); @@ -153,17 +156,14 @@ public class UsersTreeLabelProvider extends ColumnLabelProvider { return null; } return info.getVenueDescription(); - } else if (element instanceof LocalGroup) { - return ((LocalGroup) element).getName(); } return null; } @Override public Font getFont(Object element) { - if (element instanceof RosterGroup - || element instanceof SessionGroupContainer - || element instanceof LocalGroup) { + if (element instanceof RosterGroup || element instanceof SharedGroup + || element instanceof SessionGroupContainer) { // for this case do nothing, as it is not the top level of // session groups if (boldFont == null) { diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeViewerSorter.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeViewerSorter.java index dde5f3cde6..57330d5a25 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeViewerSorter.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/UsersTreeViewerSorter.java @@ -26,12 +26,12 @@ import org.jivesoftware.smack.RosterEntry; import org.jivesoftware.smack.RosterGroup; import com.raytheon.uf.viz.collaboration.comm.identity.IVenueSession; -import com.raytheon.uf.viz.collaboration.comm.provider.user.LocalGroups.LocalGroup; +import com.raytheon.uf.viz.collaboration.comm.provider.user.SharedGroup; import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId; import com.raytheon.uf.viz.collaboration.ui.data.SessionGroupContainer; /** - * TODO Add Description + * Sorts the contacts list * *
  * 
@@ -41,6 +41,7 @@ import com.raytheon.uf.viz.collaboration.ui.data.SessionGroupContainer;
  * ------------ ---------- ----------- --------------------------
  * Mar 1, 2012            rferrel     Initial creation
  * Dec  6, 2013 2561       bclement    removed ECF
+ * Jan 24, 2014 2701       bclement    removed local groups, added shared groups
  * 
  * 
* @@ -74,9 +75,12 @@ public class UsersTreeViewerSorter extends ViewerSorter { } // Groups before users. - if (e1 instanceof RosterGroup) { - if (!(e2 instanceof RosterGroup)) { + if (e1 instanceof SharedGroup) { + if (!(e2 instanceof SharedGroup)) { return -1; + } else { + return ((SharedGroup) e1).getName().compareTo( + ((SharedGroup) e2).getName()); } } else if (e1 instanceof RosterGroup) { return 1; @@ -113,17 +117,18 @@ public class UsersTreeViewerSorter extends ViewerSorter { return ((IVenueSession) e1).getVenue().toString() .compareTo(((IVenueSession) e2).getVenue().toString()); } - if (e1 instanceof LocalGroup) { - if (!(e2 instanceof LocalGroup)) { + if (e1 instanceof RosterGroup) { + if (!(e2 instanceof RosterGroup)) { return -1; } - } else if (e1 instanceof LocalGroup) { + } else if (e1 instanceof RosterGroup) { return 1; } - if (e1 instanceof LocalGroup && e2 instanceof LocalGroup) { - return ((LocalGroup) e1).getName().compareTo( - ((LocalGroup) e2).getName()); + if (e1 instanceof RosterGroup && e2 instanceof RosterGroup) { + return ((RosterGroup) e1).getName().compareTo( + ((RosterGroup) e2).getName()); } + return 0; } } diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/AddToGroupAction.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/AddToGroupAction.java index b2ce023668..5f67258136 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/AddToGroupAction.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/AddToGroupAction.java @@ -19,9 +19,6 @@ **/ package com.raytheon.uf.viz.collaboration.ui.actions; -import java.util.ArrayList; -import java.util.List; - import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ActionContributionItem; import org.eclipse.jface.action.IContributionItem; @@ -30,13 +27,13 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.jivesoftware.smack.RosterEntry; +import org.jivesoftware.smack.RosterGroup; import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType; import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent; import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection; 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.LocalGroups.LocalGroup; import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId; import com.raytheon.uf.viz.collaboration.ui.Activator; import com.raytheon.uf.viz.collaboration.ui.CreateGroupDialog; @@ -53,13 +50,13 @@ import com.raytheon.uf.viz.core.icon.IconUtil; * ------------ ---------- ----------- -------------------------- * Jul 3, 2012 bsteffen Initial creation * Dec 20, 2013 2563 bclement added support for ungrouped roster entries + * Jan 24, 2014 2701 bclement removed local groups * * * * @author bsteffen * @version 1.0 */ - public class AddToGroupAction extends Action { private final String group; @@ -83,7 +80,7 @@ public class AddToGroupAction extends Action { public AddToGroupAction(String group, UserId... users) { super(group, IconUtil.getImageDescriptor(Activator.getDefault() - .getBundle(), "local_group.gif")); + .getBundle(), "roster_group.gif")); this.group = group; this.users = users; } @@ -112,8 +109,7 @@ public class AddToGroupAction extends Action { } CollaborationConnection connection = CollaborationConnection.getConnection(); for (UserId user : users) { - connection.getContactsManager() - .addToLocalGroup(group, user); + connection.getContactsManager().addToGroup(group, user); } if (entry != null) { // the entry wasn't in a group, so the entire tree needs to be @@ -149,13 +145,7 @@ public class AddToGroupAction extends Action { private void fill() { ContactsManager contactsMgr = CollaborationConnection .getConnection().getContactsManager(); - List groups = contactsMgr.getLocalGroups(); - List usedGroups = new ArrayList(groups); - for (UserId user : users) { - usedGroups.retainAll(contactsMgr.getLocalGroups(user)); - } - groups.removeAll(usedGroups); - for (LocalGroup group : groups) { + for (RosterGroup group : contactsMgr.getGroups()) { AddToGroupAction action = new AddToGroupAction(group.getName(), users); action.setEntry(entry); diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/CreateGroupAction.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/CreateGroupAction.java index 8b1a893578..97954ec2ed 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/CreateGroupAction.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/CreateGroupAction.java @@ -39,6 +39,7 @@ import com.raytheon.uf.viz.core.icon.IconUtil; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Jul 3, 2012 bsteffen Initial creation + * Jan 24, 2014 2701 bclement removed local groups * * * @@ -74,7 +75,7 @@ public class CreateGroupAction extends Action { } for (UserId user : users) { CollaborationConnection.getConnection().getContactsManager() - .addToLocalGroup(group, user); + .addToGroup(group, user); } } } diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/DeleteGroupAction.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/DeleteGroupAction.java index a93c2129ca..85d3fb19d5 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/DeleteGroupAction.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/DeleteGroupAction.java @@ -35,6 +35,7 @@ import com.raytheon.uf.viz.core.icon.IconUtil; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Jul 3, 2012 bsteffen Initial creation + * Jan 24, 2014 2701 bclement removed local groups * * * @@ -55,6 +56,6 @@ public class DeleteGroupAction extends Action { @Override public void run() { CollaborationConnection.getConnection().getContactsManager() - .deleteLocalGroup(group); + .deleteGroup(group); } } diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/RemoveFromGroupAction.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/RemoveFromGroupAction.java index 6cf777c344..b131b1a4e5 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/RemoveFromGroupAction.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/actions/RemoveFromGroupAction.java @@ -37,6 +37,7 @@ import com.raytheon.uf.viz.core.icon.IconUtil; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Jul 3, 2012 bsteffen Initial creation + * Jan 24, 2014 2701 bclement removed local groups * * * @@ -62,7 +63,7 @@ public class RemoveFromGroupAction extends Action { ContactsManager manager = CollaborationConnection.getConnection() .getContactsManager(); for (UserId user : users) { - manager.deleteFromLocalGroup(group, user); + manager.deleteFromGroup(group, user); } } } diff --git a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/data/CollaborationGroupContainer.java b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/data/CollaborationGroupContainer.java index 8f53f96300..a04300722e 100644 --- a/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/data/CollaborationGroupContainer.java +++ b/cave/com.raytheon.uf.viz.collaboration.ui/src/com/raytheon/uf/viz/collaboration/ui/data/CollaborationGroupContainer.java @@ -21,17 +21,10 @@ package com.raytheon.uf.viz.collaboration.ui.data; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; - -import org.jivesoftware.smack.Roster; -import org.jivesoftware.smack.RosterEntry; -import org.jivesoftware.smack.RosterGroup; import com.raytheon.uf.viz.collaboration.comm.provider.session.CollaborationConnection; -import com.raytheon.uf.viz.collaboration.comm.provider.session.RosterManager; -import com.raytheon.uf.viz.collaboration.comm.provider.user.LocalGroups.LocalGroup; +import com.raytheon.uf.viz.collaboration.comm.provider.user.ContactsManager; /** * Container for collaboration information window. Includes current user, @@ -45,6 +38,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.LocalGroups.LocalGro * ------------ ---------- ----------- -------------------------- * Apr 23, 2012 mnash Initial creation * Dec 20, 2013 2563 bclement added items from server roster not in groups + * Jan 24, 2014 2701 bclement removed local groups, added shared groups * * * @@ -73,24 +67,10 @@ public class CollaborationGroupContainer { List result = new ArrayList(); result.add(connection.getUser()); result.add(sessionGroup); - RosterManager rosterManager = connection.getRosterManager(); - Roster roster = rosterManager.getRoster(); - for (RosterGroup obj : roster.getGroups()) { - result.add(obj); - } - Set usersInLocal = new HashSet(); - for (LocalGroup group : connection.getContactsManager() - .getLocalGroups()) { - usersInLocal.addAll(group.getUserNames()); - result.add(group); - } - for (RosterEntry entry : roster.getUnfiledEntries()) { - // filter out entries that aren't in a group on the server, but are - // in a local group so they don't show up twice on the contacts list - if (!usersInLocal.contains(entry.getUser())) { - result.add(entry); - } - } + ContactsManager contactsManager = connection.getContactsManager(); + result.addAll(contactsManager.getSharedGroups()); + result.addAll(contactsManager.getGroups()); + result.addAll(contactsManager.getNonGroupedContacts()); return result; } diff --git a/deltaScripts/14.3.1/removeLocalGroupsLocalization.sh b/deltaScripts/14.3.1/removeLocalGroupsLocalization.sh new file mode 100755 index 0000000000..e82956892b --- /dev/null +++ b/deltaScripts/14.3.1/removeLocalGroupsLocalization.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +echo "INFO: update started - removing collaboration local groups localization files" + +find /awips2/edex/data/utility -type f -regex '.*collaboration/localGroups.xml$' -exec rm -vf {} \; + +echo "INFO: the update has completed successfully!" + +exit 0 diff --git a/edexOsgi/com.raytheon.uf.common.util/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.util/META-INF/MANIFEST.MF index 03544cc32a..76af75665b 100644 --- a/edexOsgi/com.raytheon.uf.common.util/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.util/META-INF/MANIFEST.MF @@ -12,6 +12,7 @@ Require-Bundle: org.apache.commons.beanutils;bundle-version="1.8.3", Export-Package: com.raytheon.uf.common.util, com.raytheon.uf.common.util.algorithm, com.raytheon.uf.common.util.cache, + com.raytheon.uf.common.util.collections, com.raytheon.uf.common.util.concurrent, com.raytheon.uf.common.util.file, com.raytheon.uf.common.util.header, diff --git a/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/collections/UpdatingCollection.java b/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/collections/UpdatingCollection.java new file mode 100644 index 0000000000..f0983c08b7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/collections/UpdatingCollection.java @@ -0,0 +1,141 @@ +/** + * 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.common.util.collections; + +import java.util.Collection; + +/** + * Manages a collection that is updated upon access if the time since last + * update is greater than a specified timeout. The user of the collection only + * needs to call the 'get' method to get a read-only collection without worrying + * about updating the collection themselves. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 23, 2014 2701       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class UpdatingCollection, T> { + + private final long timeoutMillis; + + private C collection; + + private long lastUpdate; + + private boolean enabled = true; + + /** + * @param timeoutMillis + * timeout before new update in milliseconds + */ + public UpdatingCollection(long timeoutMillis) { + this.timeoutMillis = timeoutMillis; + } + + /** + * Attempt to get timeout from system property + * + * @param timeoutProp + * system property name + * @param defaultTimeoutMillis + * default timeout before new update in milliseconds + */ + public UpdatingCollection(String timeoutProp, long defaultTimeoutMillis) { + this(Long.getLong(timeoutProp, defaultTimeoutMillis)); + } + + /** + * Update collection. This method will be called if the collection is not + * initialized or if the time since last update is greater than timeout. If + * this method returns null, the time used in the timeout check will not be + * updated and the get method will return an empty collection. + * + * @return null if there was a problem with update + */ + abstract protected C update(); + + /** + * Access the collection. The returned value is unmodifiable and guaranteed + * to not be null. + * + * @return + */ + public synchronized C get() { + if (!enabled) { + return collection != null ? collection : getEmpty(); + } + C rval = collection; + long sinceLastUpdate = System.currentTimeMillis() - lastUpdate; + if (collection == null || sinceLastUpdate > timeoutMillis) { + rval = update(); + if (rval != null) { + rval = collection = wrap(rval); + lastUpdate = System.currentTimeMillis(); + } else { + rval = getEmpty(); + } + } + return rval; + } + + /** + * Wrap collection in unmodifiable collection. + * + * @return + */ + protected abstract C wrap(C collection); + + /** + * @return an empty, unmodifiable collection + */ + protected abstract C getEmpty(); + + /** + * Prevent the collection from attempting to update. + */ + public synchronized void disable() { + this.enabled = false; + } + + /** + * Allow the collection to attempt to update. + */ + public synchronized void enable() { + this.enabled = true; + } + + /** + * @return the timeout in milliseconds + */ + public long getTimeout() { + return timeoutMillis; + } + +} + diff --git a/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/collections/UpdatingSet.java b/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/collections/UpdatingSet.java new file mode 100644 index 0000000000..c45e0e1a16 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/collections/UpdatingSet.java @@ -0,0 +1,89 @@ +/** + * 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.common.util.collections; + +import java.util.Collections; +import java.util.Set; + +/** + * Manages a set that is updated upon access if the time since last update is + * greater than a specified timeout. The user of the set only needs to call the + * 'get' method to get a read-only set without worrying about updating the set + * themselves. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 23, 2014 2701       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class UpdatingSet extends UpdatingCollection, T> { + + /** + * @see UpdatingCollection#UpdatingCollection(long) + * @param timeoutMillis + * timeout before new update in milliseconds + */ + public UpdatingSet(long timeoutMillis) { + super(timeoutMillis); + } + + /** + * @see UpdatingCollection#UpdatingCollection(String, long) + * @param timeoutProp + * system property name + * @param defaultTimeoutMillis + * default timeout before new update in milliseconds + */ + public UpdatingSet(String timeoutProp, long defaultTimeoutMillis) { + super(timeoutProp, defaultTimeoutMillis); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.util.collections.UpdatingCollection#wrap(java. + * util.Collection) + */ + @Override + protected Set wrap(Set collection) { + return Collections.unmodifiableSet(collection); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.util.collections.UpdatingCollection#getEmpty() + */ + @Override + protected Set getEmpty() { + return Collections.emptySet(); + } + +}