From fffb6aaf9a6e1c31bae40126cb8bdb6302758e6f Mon Sep 17 00:00:00 2001 From: Brian Clements Date: Fri, 24 Jan 2014 08:51:28 -0600 Subject: [PATCH] Issue #2701 removed local groups from collaboration added shared groups to represent groups managed by server local group actions changed to modify roster groups code cleanup on contacts manager including removing unneeded roster manager update script to clean up localization files removed ui option to create an empty group Former-commit-id: 26ac549096a0945a901324b1b5be080ce0868d69 [formerly f615f2226fd7c08e48c3cf9341dd65bd2e18b70b [formerly 06a9db4836fa2753a913e2314a8c003380416eac]] Former-commit-id: f615f2226fd7c08e48c3cf9341dd65bd2e18b70b Former-commit-id: b86ad8ca6f0f6012bcd9abed5b624986387508a5 --- .../META-INF/MANIFEST.MF | 4 +- .../session/CollaborationConnection.java | 27 +- .../comm/provider/session/RosterManager.java | 100 --- .../comm/provider/user/ContactsManager.java | 615 +++++++++++------- .../comm/provider/user/LocalGroups.java | 131 ---- .../comm/provider/user/SharedGroup.java | 76 +++ .../comm/provider/user/UserSearch.java | 9 +- .../{local_group.gif => roster_group.gif} | Bin .../icons/{group.gif => shared_group.gif} | Bin .../ui/CollaborationGroupView.java | 69 +- .../collaboration/ui/CreateGroupDialog.java | 7 +- .../ui/UsersTreeContentProvider.java | 98 ++- .../ui/UsersTreeLabelProvider.java | 18 +- .../ui/UsersTreeViewerSorter.java | 25 +- .../ui/actions/AddToGroupAction.java | 20 +- .../ui/actions/CreateGroupAction.java | 3 +- .../ui/actions/DeleteGroupAction.java | 3 +- .../ui/actions/RemoveFromGroupAction.java | 3 +- .../ui/data/CollaborationGroupContainer.java | 32 +- .../14.3.1/removeLocalGroupsLocalization.sh | 9 + .../META-INF/MANIFEST.MF | 1 + .../util/collections/UpdatingCollection.java | 141 ++++ .../common/util/collections/UpdatingSet.java | 89 +++ 23 files changed, 816 insertions(+), 664 deletions(-) delete mode 100644 cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/RosterManager.java delete mode 100644 cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/LocalGroups.java create mode 100644 cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/user/SharedGroup.java rename cave/com.raytheon.uf.viz.collaboration.ui/icons/{local_group.gif => roster_group.gif} (100%) rename cave/com.raytheon.uf.viz.collaboration.ui/icons/{group.gif => shared_group.gif} (100%) create mode 100755 deltaScripts/14.3.1/removeLocalGroupsLocalization.sh create mode 100644 edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/collections/UpdatingCollection.java create mode 100644 edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/collections/UpdatingSet.java 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(); + } + +}