This commit is contained in:
Paul Schaub 2019-07-24 16:29:58 +02:00
parent f170438b1e
commit 4975f4a28f
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
7 changed files with 69 additions and 27 deletions

View File

@ -63,6 +63,7 @@ import org.jivesoftware.smack.roster.packet.RosterPacket;
import org.jivesoftware.smack.roster.packet.RosterPacket.Item; import org.jivesoftware.smack.roster.packet.RosterPacket.Item;
import org.jivesoftware.smack.roster.packet.RosterVer; import org.jivesoftware.smack.roster.packet.RosterVer;
import org.jivesoftware.smack.roster.packet.SubscriptionPreApproval; import org.jivesoftware.smack.roster.packet.SubscriptionPreApproval;
import org.jivesoftware.smack.roster.rosterstore.DirectoryRosterStore;
import org.jivesoftware.smack.roster.rosterstore.RosterStore; import org.jivesoftware.smack.roster.rosterstore.RosterStore;
import org.jivesoftware.smack.util.ExceptionCallback; import org.jivesoftware.smack.util.ExceptionCallback;
import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.Objects;
@ -148,7 +149,7 @@ public final class Roster extends Manager {
private static int defaultNonRosterPresenceMapMaxSize = INITIAL_DEFAULT_NON_ROSTER_PRESENCE_MAP_SIZE; private static int defaultNonRosterPresenceMapMaxSize = INITIAL_DEFAULT_NON_ROSTER_PRESENCE_MAP_SIZE;
private RosterStore rosterStore; private RosterStore<RosterItemRecord> rosterStore;
private final Map<String, RosterGroup> groups = new ConcurrentHashMap<>(); private final Map<String, RosterGroup> groups = new ConcurrentHashMap<>();
/** /**
@ -168,7 +169,7 @@ public final class Roster extends Manager {
private final Map<BareJid, Map<Resourcepart, Presence>> presenceMap = new ConcurrentHashMap<>(); private final Map<BareJid, Map<Resourcepart, Presence>> presenceMap = new ConcurrentHashMap<>();
/** /**
* Like {@link presenceMap} but for presences of entities not in our Roster. * Like presenceMap but for presences of entities not in our Roster.
*/ */
// TODO Ideally we want here to use a LRU cache like Map which will evict all superfluous items // TODO Ideally we want here to use a LRU cache like Map which will evict all superfluous items
// if their maximum size is lowered below the current item count. LruCache does not provide // if their maximum size is lowered below the current item count. LruCache does not provide
@ -182,7 +183,7 @@ public final class Roster extends Manager {
private final Set<RosterLoadedListener> rosterLoadedListeners = new LinkedHashSet<>(); private final Set<RosterLoadedListener> rosterLoadedListeners = new LinkedHashSet<>();
/** /**
* Mutually exclude roster listener invocation and changing the {@link entries} map. Also used * Mutually exclude roster listener invocation and changing the entries map. Also used
* to synchronize access to either the roster listeners or the entries map. * to synchronize access to either the roster listeners or the entries map.
*/ */
private final Object rosterListenersAndEntriesLock = new Object(); private final Object rosterListenersAndEntriesLock = new Object();
@ -491,6 +492,7 @@ public final class Roster extends Manager {
* @return true if the roster reload was initiated, false otherwise. * @return true if the roster reload was initiated, false otherwise.
* @since 4.1 * @since 4.1
*/ */
@SuppressWarnings({"unchecked", "rawtype"})
public boolean setRosterStore(RosterStore rosterStore) { public boolean setRosterStore(RosterStore rosterStore) {
this.rosterStore = rosterStore; this.rosterStore = rosterStore;
try { try {
@ -1344,7 +1346,7 @@ public final class Roster extends Manager {
} }
private void addUpdateEntry(Collection<Jid> addedEntries, Collection<Jid> updatedEntries, private void addUpdateEntry(Collection<Jid> addedEntries, Collection<Jid> updatedEntries,
Collection<Jid> unchangedEntries, RosterPacket.Item item, RosterEntry entry) { Collection<Jid> unchangedEntries, RosterItemRecord item, RosterEntry entry) {
RosterEntry oldEntry; RosterEntry oldEntry;
synchronized (rosterListenersAndEntriesLock) { synchronized (rosterListenersAndEntriesLock) {
oldEntry = entries.put(item.getJid(), entry); oldEntry = entries.put(item.getJid(), entry);
@ -1691,14 +1693,14 @@ public final class Roster extends Manager {
RosterPacket rosterPacket = (RosterPacket) packet; RosterPacket rosterPacket = (RosterPacket) packet;
// Ignore items without valid subscription type // Ignore items without valid subscription type
ArrayList<Item> validItems = new ArrayList<>(); ArrayList<RosterItemRecord> validItems = new ArrayList<>();
for (RosterPacket.Item item : rosterPacket.getRosterItems()) { for (RosterPacket.Item item : rosterPacket.getRosterItems()) {
if (hasValidSubscriptionType(item)) { if (hasValidSubscriptionType(item)) {
validItems.add(item); validItems.add(item);
} }
} }
for (RosterPacket.Item item : validItems) { for (RosterItemRecord item : validItems) {
RosterEntry entry = new RosterEntry(item, Roster.this, connection); RosterEntry entry = new RosterEntry(item, Roster.this, connection);
addUpdateEntry(addedEntries, updatedEntries, unchangedEntries, item, entry); addUpdateEntry(addedEntries, updatedEntries, unchangedEntries, item, entry);
} }
@ -1727,7 +1729,7 @@ public final class Roster extends Manager {
// means that rosterver was used and the roster hasn't changed (much) since the // means that rosterver was used and the roster hasn't changed (much) since the
// version we presented the server. So we simply load the roster from the store and // version we presented the server. So we simply load the roster from the store and
// await possible further roster pushes. // await possible further roster pushes.
List<RosterPacket.Item> storedItems = rosterStore.getEntries(); List<RosterItemRecord> storedItems = rosterStore.getEntries();
if (storedItems == null) { if (storedItems == null) {
// The roster store was corrupted. Reset the store and reload the roster without using a roster version. // The roster store was corrupted. Reset the store and reload the roster without using a roster version.
rosterStore.resetStore(); rosterStore.resetStore();
@ -1741,7 +1743,7 @@ public final class Roster extends Manager {
} }
return; return;
} }
for (RosterPacket.Item item : storedItems) { for (RosterItemRecord item : storedItems) {
RosterEntry entry = new RosterEntry(item, Roster.this, connection); RosterEntry entry = new RosterEntry(item, Roster.this, connection);
addUpdateEntry(addedEntries, updatedEntries, unchangedEntries, item, entry); addUpdateEntry(addedEntries, updatedEntries, unchangedEntries, item, entry);
} }

View File

@ -45,7 +45,7 @@ import org.jxmpp.jid.BareJid;
*/ */
public final class RosterEntry extends Manager { public final class RosterEntry extends Manager {
private RosterPacket.Item item; private RosterItemRecord item;
private final Roster roster; private final Roster roster;
/** /**
@ -55,7 +55,7 @@ public final class RosterEntry extends Manager {
* @param roster The Roster managing this entry. * @param roster The Roster managing this entry.
* @param connection a connection to the XMPP server. * @param connection a connection to the XMPP server.
*/ */
RosterEntry(RosterPacket.Item item, Roster roster, XMPPConnection connection) { RosterEntry(RosterItemRecord item, Roster roster, XMPPConnection connection) {
super(connection); super(connection);
this.item = item; this.item = item;
this.roster = roster; this.roster = roster;
@ -114,7 +114,7 @@ public final class RosterEntry extends Manager {
connection().createStanzaCollectorAndSend(packet).nextResultOrThrow(); connection().createStanzaCollectorAndSend(packet).nextResultOrThrow();
// We have received a result response to the IQ set, the name was successfully changed // We have received a result response to the IQ set, the name was successfully changed
item.setName(name); this.item = toRosterItem(this, name);
} }
/** /**
@ -122,7 +122,7 @@ public final class RosterEntry extends Manager {
* *
* @param item new item * @param item new item
*/ */
void updateItem(RosterPacket.Item item) { void updateItem(RosterItemRecord item) {
assert (item != null); assert (item != null);
this.item = item; this.item = item;
} }

View File

@ -1,4 +1,38 @@
/**
*
* Copyright 2019 Paul Schaub.
*
* 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; package org.jivesoftware.smack.roster;
import java.util.Set;
import org.jivesoftware.smack.roster.packet.RosterPacket;
import org.jxmpp.jid.BareJid;
public interface RosterItemRecord { public interface RosterItemRecord {
BareJid getJid();
String getName();
boolean isSubscriptionPending();
boolean isApproved();
Set<String> getGroupNames();
RosterPacket.ItemType getItemType();
} }

View File

@ -27,6 +27,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.NamedElement; import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.roster.RosterItemRecord;
import org.jivesoftware.smack.util.EqualsUtil; import org.jivesoftware.smack.util.EqualsUtil;
import org.jivesoftware.smack.util.HashCode; import org.jivesoftware.smack.util.HashCode;
import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.Objects;
@ -112,7 +113,7 @@ public final class RosterPacket extends IQ {
* the groups the roster item belongs to. * the groups the roster item belongs to.
*/ */
// TODO Make this class immutable. // TODO Make this class immutable.
public static final class Item implements NamedElement { public static final class Item implements NamedElement, RosterItemRecord {
/** /**
* The constant value "{@value}". * The constant value "{@value}".
@ -179,6 +180,7 @@ public final class RosterPacket extends IQ {
* *
* @return the JID. * @return the JID.
*/ */
@Override
public BareJid getJid() { public BareJid getJid() {
return jid; return jid;
} }
@ -188,6 +190,7 @@ public final class RosterPacket extends IQ {
* *
* @return the user's name. * @return the user's name.
*/ */
@Override
public String getName() { public String getName() {
return name; return name;
} }
@ -206,6 +209,7 @@ public final class RosterPacket extends IQ {
* *
* @return the roster item type. * @return the roster item type.
*/ */
@Override
public ItemType getItemType() { public ItemType getItemType() {
return itemType; return itemType;
} }
@ -223,6 +227,7 @@ public final class RosterPacket extends IQ {
this.subscriptionPending = subscriptionPending; this.subscriptionPending = subscriptionPending;
} }
@Override
public boolean isSubscriptionPending() { public boolean isSubscriptionPending() {
return subscriptionPending; return subscriptionPending;
} }
@ -232,6 +237,7 @@ public final class RosterPacket extends IQ {
* *
* @return the pre-approval state. * @return the pre-approval state.
*/ */
@Override
public boolean isApproved() { public boolean isApproved() {
return approved; return approved;
} }
@ -251,6 +257,7 @@ public final class RosterPacket extends IQ {
* *
* @return an unmodifiable set of the group names. * @return an unmodifiable set of the group names.
*/ */
@Override
public Set<String> getGroupNames() { public Set<String> getGroupNames() {
return Collections.unmodifiableSet(groupNames); return Collections.unmodifiableSet(groupNames);
} }

View File

@ -29,6 +29,7 @@ import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.jivesoftware.smack.roster.packet.RosterPacket;
import org.jivesoftware.smack.roster.packet.RosterPacket.Item; import org.jivesoftware.smack.roster.packet.RosterPacket.Item;
import org.jivesoftware.smack.roster.provider.RosterPacketProvider; import org.jivesoftware.smack.roster.provider.RosterPacketProvider;
import org.jivesoftware.smack.util.FileUtils; import org.jivesoftware.smack.util.FileUtils;
@ -47,7 +48,7 @@ import org.jxmpp.jid.Jid;
* @author Fabian Schuetz * @author Fabian Schuetz
* @author Florian Schmaus * @author Florian Schmaus
*/ */
public final class DirectoryRosterStore implements RosterStore { public final class DirectoryRosterStore implements RosterStore<RosterPacket.Item> {
private final File fileDir; private final File fileDir;
@ -182,7 +183,7 @@ public final class DirectoryRosterStore implements RosterStore {
@Override @Override
public void resetStore() { public void resetStore() {
resetEntries(Collections.<Item>emptyList(), ""); resetEntries(Collections.emptyList(), "");
} }
@SuppressWarnings("DefaultCharset") @SuppressWarnings("DefaultCharset")

View File

@ -19,7 +19,7 @@ package org.jivesoftware.smack.roster.rosterstore;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.jivesoftware.smack.roster.packet.RosterPacket; import org.jivesoftware.smack.roster.RosterItemRecord;
import org.jxmpp.jid.Jid; import org.jxmpp.jid.Jid;
@ -28,22 +28,22 @@ import org.jxmpp.jid.Jid;
* roster versioning as per RFC 6121. * roster versioning as per RFC 6121.
*/ */
public interface RosterStore { public interface RosterStore<I extends RosterItemRecord> {
/** /**
* This method returns a list of all roster items contained in this store. If there was an error while loading the store, then <code>null</code> is returned. * This method returns a list of all roster items contained in this store. If there was an error while loading the store, then <code>null</code> is returned.
* *
* @return List of {@link org.jivesoftware.smack.roster.RosterEntry} or <code>null</code>. * @return List of {@link RosterItemRecord} or <code>null</code>.
*/ */
List<RosterPacket.Item> getEntries(); List<I> getEntries();
/** /**
* This method returns the roster item in this store for the given JID. * This method returns the roster item in this store for the given JID.
* *
* @param bareJid The bare JID of the RosterEntry * @param bareJid The bare JID of the RosterEntry
* @return The {@link org.jivesoftware.smack.roster.RosterEntry} which belongs to that user * @return The {@link RosterItemRecord} which belongs to that user
*/ */
RosterPacket.Item getEntry(Jid bareJid); I getEntry(Jid bareJid);
/** /**
* This method returns the version number as specified by the "ver" attribute * This method returns the version number as specified by the "ver" attribute
@ -60,7 +60,7 @@ public interface RosterStore {
* @param version the new roster version * @param version the new roster version
* @return True if successful * @return True if successful
*/ */
boolean addEntry(RosterPacket.Item item, String version); boolean addEntry(I item, String version);
/** /**
* This method updates the store so that it contains only the given entries. * This method updates the store so that it contains only the given entries.
@ -69,7 +69,7 @@ public interface RosterStore {
* @param version the new roster version * @param version the new roster version
* @return True if successful * @return True if successful
*/ */
boolean resetEntries(Collection<RosterPacket.Item> items, String version); boolean resetEntries(Collection<I> items, String version);
/** /**
* Removes an entry from the store. * Removes an entry from the store.

View File

@ -60,6 +60,7 @@ public class RosterVersioningTest {
private DummyConnection connection; private DummyConnection connection;
private Roster roster; private Roster roster;
private DirectoryRosterStore store;
private TestRosterListener rosterListener; private TestRosterListener rosterListener;
@Rule @Rule
@ -67,7 +68,7 @@ public class RosterVersioningTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
DirectoryRosterStore store = DirectoryRosterStore.init(tmpFolder.newFolder("store")); store = DirectoryRosterStore.init(tmpFolder.newFolder("store"));
populateStore(store); populateStore(store);
connection = new DummyConnection(); connection = new DummyConnection();
@ -163,7 +164,6 @@ public class RosterVersioningTest {
assertNotNull("Roster contains vaglaf entry", entry); assertNotNull("Roster contains vaglaf entry", entry);
assertEquals("vaglaf entry in roster equals the sent entry", vaglafItem, RosterEntry.toRosterItem(entry)); assertEquals("vaglaf entry in roster equals the sent entry", vaglafItem, RosterEntry.toRosterItem(entry));
RosterStore store = roster.getRosterStore();
assertEquals("Size of store", 1, store.getEntries().size()); assertEquals("Size of store", 1, store.getEntries().size());
Item item = store.getEntry(vaglafItem.getJid()); Item item = store.getEntry(vaglafItem.getJid());
assertNotNull("Store contains vaglaf entry", item); assertNotNull("Store contains vaglaf entry", item);
@ -179,8 +179,6 @@ public class RosterVersioningTest {
answerWithEmptyRosterResult(); answerWithEmptyRosterResult();
rosterListener.waitAndReset(); rosterListener.waitAndReset();
RosterStore store = roster.getRosterStore();
// Simulate a roster push adding vaglaf // Simulate a roster push adding vaglaf
{ {
RosterPacket rosterPush = new RosterPacket(); RosterPacket rosterPush = new RosterPacket();