1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2025-09-09 18:29:45 +02:00

Inroduce AsyncButOrdered

This commit is contained in:
Florian Schmaus 2018-04-08 21:21:50 +02:00
parent 1acfd872a7
commit 476fdf99a1
11 changed files with 414 additions and 272 deletions

View file

@ -22,6 +22,7 @@ import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.jivesoftware.smack.AsyncButOrdered;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.StanzaListener;
@ -91,6 +92,8 @@ public final class ChatManager extends Manager {
private final Set<OutgoingChatMessageListener> outgoingListeners = new CopyOnWriteArraySet<>();
private final AsyncButOrdered<Chat> asyncButOrdered = new AsyncButOrdered<>();
private boolean xhtmlIm;
private ChatManager(final XMPPConnection connection) {
@ -98,7 +101,7 @@ public final class ChatManager extends Manager {
connection.addSyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) {
Message message = (Message) stanza;
final Message message = (Message) stanza;
if (!shouldAcceptMessage(message)) {
return;
}
@ -109,9 +112,15 @@ public final class ChatManager extends Manager {
final Chat chat = chatWith(bareFrom);
chat.lockedResource = fullFrom;
for (IncomingChatMessageListener listener : incomingListeners) {
listener.newIncomingMessage(bareFrom, message, chat);
}
asyncButOrdered.performAsyncButOrdered(chat, new Runnable() {
@Override
public void run() {
for (IncomingChatMessageListener listener : incomingListeners) {
listener.newIncomingMessage(bareFrom, message, chat);
}
}
});
}
}, INCOMING_MESSAGE_FILTER);

View file

@ -26,6 +26,7 @@ import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.AsyncButOrdered;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.StanzaListener;
@ -85,6 +86,8 @@ public final class ChatStateManager extends Manager {
*/
private final Map<Chat, ChatState> chatStates = new WeakHashMap<>();
private final AsyncButOrdered<Chat> asyncButOrdered = new AsyncButOrdered<>();
/**
* Returns the ChatStateManager related to the XMPPConnection and it will create one if it does
* not yet exist.
@ -129,15 +132,15 @@ public final class ChatStateManager extends Manager {
}
});
connection.addAsyncStanzaListener(new StanzaListener() {
connection.addSyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) {
Message message = (Message) stanza;
final Message message = (Message) stanza;
EntityFullJid fullFrom = message.getFrom().asEntityFullJidIfPossible();
EntityBareJid bareFrom = fullFrom.asEntityBareJid();
Chat chat = ChatManager.getInstanceFor(connection()).chatWith(bareFrom);
final Chat chat = ChatManager.getInstanceFor(connection()).chatWith(bareFrom);
ExtensionElement extension = message.getExtension(NAMESPACE);
String chatStateElementName = extension.getElementName();
@ -149,6 +152,7 @@ public final class ChatStateManager extends Manager {
LOGGER.log(Level.WARNING, "Invalid chat state element name: " + chatStateElementName, ex);
return;
}
final ChatState finalState = state;
List<ChatStateListener> listeners;
synchronized (chatStateListeners) {
@ -156,9 +160,15 @@ public final class ChatStateManager extends Manager {
listeners.addAll(chatStateListeners);
}
for (ChatStateListener listener : listeners) {
listener.stateChanged(chat, state, message);
}
final List<ChatStateListener> finalListeners = listeners;
asyncButOrdered.performAsyncButOrdered(chat, new Runnable() {
@Override
public void run() {
for (ChatStateListener listener : finalListeners) {
listener.stateChanged(chat, finalState, message);
}
}
});
}
}, INCOMING_CHAT_STATE_FILTER);

View file

@ -27,6 +27,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.AsyncButOrdered;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.PresenceListener;
import org.jivesoftware.smack.SmackException;
@ -141,6 +142,8 @@ public class MultiUserChat {
private final StanzaListener presenceListener;
private final StanzaListener subjectListener;
private static final AsyncButOrdered<MultiUserChat> asyncButOrdered = new AsyncButOrdered<>();
private static final StanzaFilter DECLINE_FILTER = new AndFilter(MessageTypeFilter.NORMAL,
new StanzaExtensionFilter(MUCUser.ELEMENT, MUCUser.NAMESPACE));
private final StanzaListener declinesListener;
@ -161,10 +164,16 @@ public class MultiUserChat {
messageListener = new StanzaListener() {
@Override
public void processStanza(Stanza packet) throws NotConnectedException {
Message message = (Message) packet;
for (MessageListener listener : messageListeners) {
listener.processMessage(message);
}
final Message message = (Message) packet;
asyncButOrdered.performAsyncButOrdered(MultiUserChat.this, new Runnable() {
@Override
public void run() {
for (MessageListener listener : messageListeners) {
listener.processMessage(message);
}
}
});
}
};
@ -172,84 +181,96 @@ public class MultiUserChat {
subjectListener = new StanzaListener() {
@Override
public void processStanza(Stanza packet) {
Message msg = (Message) packet;
EntityFullJid from = msg.getFrom().asEntityFullJidIfPossible();
final Message msg = (Message) packet;
final EntityFullJid from = msg.getFrom().asEntityFullJidIfPossible();
// Update the room subject
subject = msg.getSubject();
// Fire event for subject updated listeners
for (SubjectUpdatedListener listener : subjectUpdatedListeners) {
listener.subjectUpdated(subject, from);
}
asyncButOrdered.performAsyncButOrdered(MultiUserChat.this, new Runnable() {
@Override
public void run() {
// Fire event for subject updated listeners
for (SubjectUpdatedListener listener : subjectUpdatedListeners) {
listener.subjectUpdated(msg.getSubject(), from);
}
}
});
}
};
// Create a listener for all presence updates.
presenceListener = new StanzaListener() {
@Override
public void processStanza(Stanza packet) {
Presence presence = (Presence) packet;
public void processStanza(final Stanza packet) {
final Presence presence = (Presence) packet;
final EntityFullJid from = presence.getFrom().asEntityFullJidIfPossible();
if (from == null) {
LOGGER.warning("Presence not from a full JID: " + presence.getFrom());
return;
}
String myRoomJID = MultiUserChat.this.room + "/" + nickname;
boolean isUserStatusModification = presence.getFrom().equals(myRoomJID);
switch (presence.getType()) {
case available:
Presence oldPresence = occupantsMap.put(from, presence);
if (oldPresence != null) {
// Get the previous occupant's affiliation & role
MUCUser mucExtension = MUCUser.from(oldPresence);
MUCAffiliation oldAffiliation = mucExtension.getItem().getAffiliation();
MUCRole oldRole = mucExtension.getItem().getRole();
// Get the new occupant's affiliation & role
mucExtension = MUCUser.from(packet);
MUCAffiliation newAffiliation = mucExtension.getItem().getAffiliation();
MUCRole newRole = mucExtension.getItem().getRole();
// Fire role modification events
checkRoleModifications(oldRole, newRole, isUserStatusModification, from);
// Fire affiliation modification events
checkAffiliationModifications(
oldAffiliation,
newAffiliation,
isUserStatusModification,
from);
}
else {
// A new occupant has joined the room
if (!isUserStatusModification) {
for (ParticipantStatusListener listener : participantStatusListeners) {
listener.joined(from);
final String myRoomJID = MultiUserChat.this.room + "/" + nickname;
final boolean isUserStatusModification = presence.getFrom().equals(myRoomJID);
asyncButOrdered.performAsyncButOrdered(MultiUserChat.this, new Runnable() {
@Override
public void run() {
switch (presence.getType()) {
case available:
Presence oldPresence = occupantsMap.put(from, presence);
if (oldPresence != null) {
// Get the previous occupant's affiliation & role
MUCUser mucExtension = MUCUser.from(oldPresence);
MUCAffiliation oldAffiliation = mucExtension.getItem().getAffiliation();
MUCRole oldRole = mucExtension.getItem().getRole();
// Get the new occupant's affiliation & role
mucExtension = MUCUser.from(packet);
MUCAffiliation newAffiliation = mucExtension.getItem().getAffiliation();
MUCRole newRole = mucExtension.getItem().getRole();
// Fire role modification events
checkRoleModifications(oldRole, newRole, isUserStatusModification, from);
// Fire affiliation modification events
checkAffiliationModifications(
oldAffiliation,
newAffiliation,
isUserStatusModification,
from);
}
else {
// A new occupant has joined the room
if (!isUserStatusModification) {
for (ParticipantStatusListener listener : participantStatusListeners) {
listener.joined(from);
}
}
}
break;
case unavailable:
occupantsMap.remove(from);
MUCUser mucUser = MUCUser.from(packet);
if (mucUser != null && mucUser.hasStatus()) {
// Fire events according to the received presence code
checkPresenceCode(
mucUser.getStatus(),
presence.getFrom().equals(myRoomJID),
mucUser,
from);
} else {
// An occupant has left the room
if (!isUserStatusModification) {
for (ParticipantStatusListener listener : participantStatusListeners) {
listener.left(from);
}
}
}
break;
default:
break;
}
for (PresenceListener listener : presenceListeners) {
listener.processPresence(presence);
}
}
break;
case unavailable:
occupantsMap.remove(from);
MUCUser mucUser = MUCUser.from(packet);
if (mucUser != null && mucUser.hasStatus()) {
// Fire events according to the received presence code
checkPresenceCode(
mucUser.getStatus(),
presence.getFrom().equals(myRoomJID),
mucUser,
from);
} else {
// An occupant has left the room
if (!isUserStatusModification) {
for (ParticipantStatusListener listener : participantStatusListeners) {
listener.left(from);
}
}
}
break;
default:
break;
}
for (PresenceListener listener : presenceListeners) {
listener.processPresence(presence);
}
});
}
};

View file

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software, 2015 Florian Schmaus
* Copyright 2003-2007 Jive Software, 2015-2018 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.jivesoftware.smack.AsyncButOrdered;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
@ -86,6 +87,8 @@ public final class PEPManager extends Manager {
private final Set<PEPListener> pepListeners = new CopyOnWriteArraySet<>();
private final AsyncButOrdered<EntityBareJid> asyncButOrdered = new AsyncButOrdered<>();
/**
* Creates a new PEP exchange manager.
*
@ -96,14 +99,19 @@ public final class PEPManager extends Manager {
StanzaListener packetListener = new StanzaListener() {
@Override
public void processStanza(Stanza stanza) {
Message message = (Message) stanza;
EventElement event = EventElement.from(stanza);
final Message message = (Message) stanza;
final EventElement event = EventElement.from(stanza);
assert (event != null);
EntityBareJid from = message.getFrom().asEntityBareJidIfPossible();
final EntityBareJid from = message.getFrom().asEntityBareJidIfPossible();
assert (from != null);
for (PEPListener listener : pepListeners) {
listener.eventReceived(from, event, message);
}
asyncButOrdered.performAsyncButOrdered(from, new Runnable() {
@Override
public void run() {
for (PEPListener listener : pepListeners) {
listener.eventReceived(from, event, message);
}
}
});
}
};
// TODO Add filter to check if from supports PubSub as per xep163 2 2.4

View file

@ -521,6 +521,7 @@ public abstract class Node {
EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract");
EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString());
// TODO: Use AsyncButOrdered (with Node as Key?)
pubSubManager.getConnection().addSyncStanzaListener(delListener, new OrFilter(deleteItem, purge));
}
@ -588,6 +589,7 @@ public abstract class Node {
EventElement event = packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
ItemsExtension itemsElem = (ItemsExtension) event.getEvent();
ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), itemsElem.getItems(), getSubscriptionIds(packet), DelayInformationManager.getDelayTimestamp(packet));
// TODO: Use AsyncButOrdered (with Node as Key?)
listener.handlePublishedItems(eventItems);
}
}
@ -650,6 +652,7 @@ public abstract class Node {
EventElement event = packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
ConfigurationEvent config = (ConfigurationEvent) event.getEvent();
// TODO: Use AsyncButOrdered (with Node as Key?)
listener.handleNodeConfiguration(config);
}
}