mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 14:22:05 +01:00
Add Roster.getEntriesAndAddListener(RosterListener,RosterEntries)
This commit is contained in:
parent
86ea027301
commit
7348e8bc8b
2 changed files with 96 additions and 21 deletions
|
@ -59,6 +59,7 @@ import org.jivesoftware.smack.roster.packet.RosterPacket;
|
|||
import org.jivesoftware.smack.roster.packet.RosterVer;
|
||||
import org.jivesoftware.smack.roster.packet.RosterPacket.Item;
|
||||
import org.jivesoftware.smack.roster.rosterstore.RosterStore;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jxmpp.util.XmppStringUtils;
|
||||
|
||||
/**
|
||||
|
@ -123,11 +124,22 @@ public class Roster extends Manager {
|
|||
|
||||
private RosterStore rosterStore;
|
||||
private final Map<String, RosterGroup> groups = new ConcurrentHashMap<String, RosterGroup>();
|
||||
|
||||
/**
|
||||
* Concurrent hash map from JID to its roster entry.
|
||||
*/
|
||||
private final Map<String,RosterEntry> entries = new ConcurrentHashMap<String,RosterEntry>();
|
||||
|
||||
private final Set<RosterEntry> unfiledEntries = new CopyOnWriteArraySet<>();
|
||||
private final Set<RosterListener> rosterListeners = new LinkedHashSet<>();
|
||||
private final Map<String, Map<String, Presence>> presenceMap = new ConcurrentHashMap<String, Map<String, Presence>>();
|
||||
|
||||
/**
|
||||
* Mutually exclude roster listener invocation and changing the {@link entries} map. Also used
|
||||
* to synchronize access to either the roster listeners or the entries map.
|
||||
*/
|
||||
private final Object rosterListenersAndEntriesLock = new Object();
|
||||
|
||||
// The roster is marked as initialized when at least a single roster packet
|
||||
// has been received and processed.
|
||||
private boolean loaded = false;
|
||||
|
@ -354,9 +366,12 @@ public class Roster extends Manager {
|
|||
*
|
||||
* @param rosterListener a roster listener.
|
||||
* @return true if the listener was not already added.
|
||||
* @see #getEntriesAndAddListener(RosterListener, RosterEntries)
|
||||
*/
|
||||
public boolean addRosterListener(RosterListener rosterListener) {
|
||||
return rosterListeners.add(rosterListener);
|
||||
synchronized (rosterListenersAndEntriesLock) {
|
||||
return rosterListeners.add(rosterListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -367,7 +382,9 @@ public class Roster extends Manager {
|
|||
* @return true if the listener was active and got removed.
|
||||
*/
|
||||
public boolean removeRosterListener(RosterListener rosterListener) {
|
||||
return rosterListeners.remove(rosterListener);
|
||||
synchronized (rosterListenersAndEntriesLock) {
|
||||
return rosterListeners.remove(rosterListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -481,6 +498,33 @@ public class Roster extends Manager {
|
|||
return getEntries().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a roster listener and invoke the roster entries with all entries of the roster.
|
||||
* <p>
|
||||
* The method guarantees that the listener is only invoked after
|
||||
* {@link RosterEntries#rosterEntires(Collection)} has been invoked, and that all roster events
|
||||
* that happen while <code>rosterEntires(Collection) </code> is called are queued until the
|
||||
* method returns.
|
||||
* </p>
|
||||
* <p>
|
||||
* This guarantee makes this the ideal method to e.g. populate a UI element with the roster while
|
||||
* installing a {@link RosterListener} to listen for subsequent roster events.
|
||||
* </p>
|
||||
*
|
||||
* @param rosterListener the listener to install
|
||||
* @param rosterEntries the roster entries callback interface
|
||||
* @since 4.1
|
||||
*/
|
||||
public void getEntriesAndAddListener(RosterListener rosterListener, RosterEntries rosterEntries) {
|
||||
Objects.requireNonNull(rosterListener, "listener must not be null");
|
||||
Objects.requireNonNull(rosterEntries, "rosterEntries must not be null");
|
||||
|
||||
synchronized (rosterListenersAndEntriesLock) {
|
||||
rosterEntries.rosterEntires(entries.values());
|
||||
addRosterListener(rosterListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of all entries in the roster, including entries
|
||||
* that don't belong to any groups.
|
||||
|
@ -488,14 +532,13 @@ public class Roster extends Manager {
|
|||
* @return all entries in the roster.
|
||||
*/
|
||||
public Set<RosterEntry> getEntries() {
|
||||
Set<RosterEntry> allEntries = new HashSet<RosterEntry>();
|
||||
// Loop through all roster groups and add their entries to the answer
|
||||
for (RosterGroup rosterGroup : getGroups()) {
|
||||
allEntries.addAll(rosterGroup.getEntries());
|
||||
Set<RosterEntry> allEntries;
|
||||
synchronized (rosterListenersAndEntriesLock) {
|
||||
allEntries = new HashSet<>(entries.size());
|
||||
for (RosterEntry entry : entries.values()) {
|
||||
allEntries.add(entry);
|
||||
}
|
||||
}
|
||||
// Add the roster unfiled entries to the answer
|
||||
allEntries.addAll(unfiledEntries);
|
||||
|
||||
return allEntries;
|
||||
}
|
||||
|
||||
|
@ -896,15 +939,17 @@ public class Roster extends Manager {
|
|||
*/
|
||||
private void fireRosterChangedEvent(final Collection<String> addedEntries, final Collection<String> updatedEntries,
|
||||
final Collection<String> deletedEntries) {
|
||||
for (RosterListener listener : rosterListeners) {
|
||||
if (!addedEntries.isEmpty()) {
|
||||
listener.entriesAdded(addedEntries);
|
||||
}
|
||||
if (!updatedEntries.isEmpty()) {
|
||||
listener.entriesUpdated(updatedEntries);
|
||||
}
|
||||
if (!deletedEntries.isEmpty()) {
|
||||
listener.entriesDeleted(deletedEntries);
|
||||
synchronized (rosterListenersAndEntriesLock) {
|
||||
for (RosterListener listener : rosterListeners) {
|
||||
if (!addedEntries.isEmpty()) {
|
||||
listener.entriesAdded(addedEntries);
|
||||
}
|
||||
if (!updatedEntries.isEmpty()) {
|
||||
listener.entriesUpdated(updatedEntries);
|
||||
}
|
||||
if (!deletedEntries.isEmpty()) {
|
||||
listener.entriesDeleted(deletedEntries);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -915,14 +960,19 @@ public class Roster extends Manager {
|
|||
* @param presence the presence change.
|
||||
*/
|
||||
private void fireRosterPresenceEvent(final Presence presence) {
|
||||
for (RosterListener listener : rosterListeners) {
|
||||
listener.presenceChanged(presence);
|
||||
synchronized (rosterListenersAndEntriesLock) {
|
||||
for (RosterListener listener : rosterListeners) {
|
||||
listener.presenceChanged(presence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addUpdateEntry(Collection<String> addedEntries, Collection<String> updatedEntries,
|
||||
Collection<String> unchangedEntries, RosterPacket.Item item, RosterEntry entry) {
|
||||
RosterEntry oldEntry = entries.put(item.getUser(), entry);
|
||||
RosterEntry oldEntry;
|
||||
synchronized (rosterListenersAndEntriesLock) {
|
||||
oldEntry = entries.put(item.getUser(), entry);
|
||||
}
|
||||
if (oldEntry == null) {
|
||||
addedEntries.add(item.getUser());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2015 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smack.roster;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface RosterEntries {
|
||||
|
||||
public void rosterEntires(Collection<RosterEntry> rosterEntries);
|
||||
|
||||
}
|
Loading…
Reference in a new issue