use of org.jivesoftware.smack.filter.AndFilter in project Smack by igniterealtime.
the class XmppConnectionStressTest method run.
public void run(List<? extends XMPPConnection> connections, final long replyTimeoutMillis) throws InterruptedException, NotAllMessagesReceivedException, ErrorsWhileSendingOrReceivingException {
final MultiMap<XMPPConnection, Message> messages = new MultiMap<>();
final Random random = new Random(configuration.seed);
final Map<XMPPConnection, Exception> sendExceptions = new ConcurrentHashMap<>();
final Map<XMPPConnection, Exception> receiveExceptions = new ConcurrentHashMap<>();
waitStart = -1;
for (XMPPConnection fromConnection : connections) {
MultiMap<XMPPConnection, Message> toConnectionMessages = new MultiMap<>();
for (XMPPConnection toConnection : connections) {
for (int i = 0; i < configuration.messagesPerConnection; i++) {
MessageBuilder messageBuilder = fromConnection.getStanzaFactory().buildMessageStanza();
messageBuilder.to(toConnection.getUser());
final int payloadChunkCount;
if (configuration.maxPayloadChunks == 0) {
payloadChunkCount = 0;
} else {
payloadChunkCount = random.nextInt(configuration.maxPayloadChunks) + 1;
}
for (int c = 0; c < payloadChunkCount; c++) {
int payloadChunkSize = random.nextInt(configuration.maxPayloadChunkSize) + 1;
String payloadCunk = StringUtils.randomString(payloadChunkSize, random);
JivePropertiesManager.addProperty(messageBuilder, "payload-chunk-" + c, payloadCunk);
}
JivePropertiesManager.addProperty(messageBuilder, MESSAGE_NUMBER_PROPERTY, i);
Message message = messageBuilder.build();
toConnectionMessages.put(toConnection, message);
}
}
if (configuration.intermixMessages) {
while (!toConnectionMessages.isEmpty()) {
int next = random.nextInt(connections.size());
Message message = null;
while (message == null) {
XMPPConnection toConnection = connections.get(next);
message = toConnectionMessages.getFirst(toConnection);
next = (next + 1) % connections.size();
}
messages.put(fromConnection, message);
}
} else {
for (XMPPConnection toConnection : connections) {
for (Message message : toConnectionMessages.getAll(toConnection)) {
messages.put(fromConnection, message);
}
}
}
}
Semaphore receivedSemaphore = new Semaphore(-connections.size() + 1);
Map<XMPPConnection, Map<EntityFullJid, boolean[]>> receiveMarkers = new ConcurrentHashMap<>(connections.size());
for (XMPPConnection connection : connections) {
final Map<EntityFullJid, boolean[]> myReceiveMarkers = new HashMap<>(connections.size());
receiveMarkers.put(connection, myReceiveMarkers);
for (XMPPConnection otherConnection : connections) {
boolean[] fromMarkers = new boolean[configuration.messagesPerConnection];
myReceiveMarkers.put(otherConnection.getUser(), fromMarkers);
}
connection.addSyncStanzaListener(new StanzaListener() {
@Override
public void processStanza(Stanza stanza) {
waitStart = System.currentTimeMillis();
EntityFullJid from = stanza.getFrom().asEntityFullJidOrThrow();
Message message = (Message) stanza;
JivePropertiesExtension extension = JivePropertiesExtension.from(message);
Integer messageNumber = (Integer) extension.getProperty(MESSAGE_NUMBER_PROPERTY);
boolean[] fromMarkers = myReceiveMarkers.get(from);
// Sanity check: All markers before must be true, all markers including the messageNumber marker must be false.
for (int i = 0; i < fromMarkers.length; i++) {
final String inOrderViolation;
if (i < messageNumber && !fromMarkers[i]) {
// A previous message was missing.
inOrderViolation = "not yet message #";
} else if (i >= messageNumber && fromMarkers[i]) {
// We already received a new message.
// TODO: Can it ever happen that this is taken? Wouldn't we prior run into the "a previous
// message is missing" case?
inOrderViolation = "we already received a later (or the same) message #";
} else {
continue;
}
StringBuilder exceptionMessage = new StringBuilder();
exceptionMessage.append("We received message #").append(messageNumber).append(" but ");
exceptionMessage.append(inOrderViolation);
exceptionMessage.append(i);
exceptionMessage.append("\nMessage with id ").append(stanza.getStanzaId()).append(" from ").append(from).append(" to ").append(stanza.getTo()).append('\n');
exceptionMessage.append("From Markers: ").append(Arrays.toString(fromMarkers)).append('\n');
Exception exception = new Exception(exceptionMessage.toString());
receiveExceptions.put(connection, exception);
// TODO: Current Smack design does not guarantee that the listener won't be invoked again.
// This is because the decission to invoke a sync listeners is done at a different place
// then invoking the listener.
connection.removeSyncStanzaListener(this);
receivedSemaphore.release();
// TODO: Do not return here?
return;
}
fromMarkers[messageNumber] = true;
for (boolean[] markers : myReceiveMarkers.values()) {
if (BooleansUtils.contains(markers, false)) {
// receivedSemaphore.
return;
}
}
// All markers set to true, this means we received all messages.
receivedSemaphore.release();
}
}, new AndFilter(MessageTypeFilter.NORMAL, new StanzaExtensionFilter(JivePropertiesExtension.ELEMENT, JivePropertiesExtension.NAMESPACE)));
}
Semaphore sendSemaphore = new Semaphore(-connections.size() + 1);
for (XMPPConnection connection : connections) {
Async.go(() -> {
List<Message> messagesToSend;
synchronized (messages) {
messagesToSend = messages.getAll(connection);
}
try {
for (Message messageToSend : messagesToSend) {
connection.sendStanza(messageToSend);
}
} catch (NotConnectedException | InterruptedException e) {
sendExceptions.put(connection, e);
} finally {
sendSemaphore.release();
}
});
}
sendSemaphore.acquire();
if (waitStart < 0) {
waitStart = System.currentTimeMillis();
}
boolean acquired;
do {
long acquireWait = waitStart + replyTimeoutMillis - System.currentTimeMillis();
acquired = receivedSemaphore.tryAcquire(acquireWait, TimeUnit.MILLISECONDS);
} while (!acquired && System.currentTimeMillis() < waitStart + replyTimeoutMillis);
if (!acquired && receiveExceptions.isEmpty() && sendExceptions.isEmpty()) {
throw new StressTestFailedException.NotAllMessagesReceivedException(receiveMarkers, connections);
}
if (!receiveExceptions.isEmpty() || !sendExceptions.isEmpty()) {
throw new StressTestFailedException.ErrorsWhileSendingOrReceivingException(sendExceptions, receiveExceptions);
}
// Test successful.
}
use of org.jivesoftware.smack.filter.AndFilter in project Smack by igniterealtime.
the class EntityCapsTest method testEntityCaps.
@SmackIntegrationTest
public void testEntityCaps() throws XMPPException, InterruptedException, NoResponseException, NotConnectedException, TimeoutException {
final String dummyFeature = getNewDummyFeature();
dropWholeEntityCapsCache();
performActionAndWaitUntilStanzaReceived(new Runnable() {
@Override
public void run() {
sdmTwo.addFeature(dummyFeature);
}
}, connection, new AndFilter(PresenceTypeFilter.AVAILABLE, FromMatchesFilter.create(conTwo.getUser())));
waitUntilTrue(new Condition() {
@Override
public boolean evaluate() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
DiscoverInfo info = sdmOne.discoverInfo(conTwo.getUser());
return info.containsFeature(dummyFeature);
}
});
DiscoverInfo info = sdmOne.discoverInfo(conTwo.getUser());
String u1ver = EntityCapsManager.getNodeVersionByJid(conTwo.getUser());
assertNotNull(u1ver);
DiscoverInfo entityInfo = EntityCapsManager.CAPS_CACHE.lookup(u1ver);
assertNotNull(entityInfo);
assertEquals(info.toXML().toString(), entityInfo.toXML().toString());
}
use of org.jivesoftware.smack.filter.AndFilter in project Smack by igniterealtime.
the class EntityCapsTest method testLocalEntityCaps.
@SmackIntegrationTest
public void testLocalEntityCaps() throws InterruptedException, NoResponseException, XMPPErrorException, NotConnectedException {
final String dummyFeature = getNewDummyFeature();
DiscoverInfo info = EntityCapsManager.getDiscoveryInfoByNodeVer(ecmTwo.getLocalNodeVer());
assertFalse(info.containsFeature(dummyFeature));
dropWholeEntityCapsCache();
performActionAndWaitUntilStanzaReceived(new Runnable() {
@Override
public void run() {
// This should cause a new presence stanza from con1 with and updated
// 'ver' String
sdmTwo.addFeature(dummyFeature);
}
}, conOne, new AndFilter(PresenceTypeFilter.AVAILABLE, FromMatchesFilter.create(conTwo.getUser())));
// The presence stanza should get received by con0 and the data should
// be recorded in the map
// Note that while both connections use the same static Entity Caps
// cache,
// it's assured that *not* con1 added the data to the Entity Caps cache.
// Every time the entities features
// and identities change only a new caps 'ver' is calculated and send
// with the presence stanza
// The other connection has to receive this stanza and record the
// information in order for this test to succeed.
info = EntityCapsManager.getDiscoveryInfoByNodeVer(ecmTwo.getLocalNodeVer());
assertNotNull(info);
assertTrue(info.containsFeature(dummyFeature));
}
use of org.jivesoftware.smack.filter.AndFilter in project Smack by igniterealtime.
the class Workgroup method isAvailable.
/**
* Returns true if the workgroup is available for receiving new requests. The workgroup will be
* available only when agents are available for this workgroup.
*
* @return true if the workgroup is available for receiving new requests.
* @throws XMPPErrorException if there was an XMPP error returned.
* @throws NoResponseException if there was no response from the remote entity.
* @throws NotConnectedException if the XMPP connection is not connected.
* @throws InterruptedException if the calling thread was interrupted.
*/
public boolean isAvailable() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
Presence directedPresence = connection.getStanzaFactory().buildPresenceStanza().ofType(Presence.Type.available).to(workgroupJID).build();
StanzaFilter typeFilter = new StanzaTypeFilter(Presence.class);
StanzaFilter fromFilter = FromMatchesFilter.create(workgroupJID);
StanzaCollector collector = connection.createStanzaCollectorAndSend(new AndFilter(fromFilter, typeFilter), directedPresence);
Presence response = collector.nextResultOrThrow();
return Presence.Type.available == response.getType();
}
use of org.jivesoftware.smack.filter.AndFilter in project Smack by igniterealtime.
the class AgentSession method setStatus.
/**
* Sets the agent's current status with the workgroup. The presence mode affects how offers
* are routed to the agent. The possible presence modes with their meanings are as follows:<ul>
*
* <li>Presence.Mode.AVAILABLE -- (Default) the agent is available for more chats
* (equivalent to Presence.Mode.CHAT).
* <li>Presence.Mode.DO_NOT_DISTURB -- the agent is busy and should not be disturbed.
* However, special case, or extreme urgency chats may still be offered to the agent.
* <li>Presence.Mode.AWAY -- the agent is not available and should not
* have a chat routed to them (equivalent to Presence.Mode.EXTENDED_AWAY).</ul>
*
* @param presenceMode the presence mode of the agent.
* @param status sets the status message of the presence update.
* @throws XMPPErrorException if there was an XMPP error returned.
* @throws NoResponseException if there was no response from the remote entity.
* @throws NotConnectedException if the XMPP connection is not connected.
* @throws InterruptedException if the calling thread was interrupted.
* @throws IllegalStateException if the agent is not online with the workgroup.
*/
public void setStatus(Presence.Mode presenceMode, String status) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
if (!online) {
throw new IllegalStateException("Cannot set status when the agent is not online.");
}
if (presenceMode == null) {
presenceMode = Presence.Mode.available;
}
this.presenceMode = presenceMode;
PresenceBuilder presenceBuilder = connection.getStanzaFactory().buildPresenceStanza().ofType(Presence.Type.available).setMode(presenceMode).to(getWorkgroupJID());
if (status != null) {
presenceBuilder.setStatus(status);
}
Presence presence = presenceBuilder.build();
presence.addExtension(new MetaData(this.metaData));
StanzaCollector collector = this.connection.createStanzaCollectorAndSend(new AndFilter(new StanzaTypeFilter(Presence.class), FromMatchesFilter.create(workgroupJID)), presence);
collector.nextResultOrThrow();
}
Aggregations