mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-12-22 20:47:57 +01:00
Add support for IoT Friend approvals
This adds supports for an experimental protocol flow where a pending friend request's decission is later on deliverd to the requestor after the owner made its decission.
This commit is contained in:
parent
5a2326a856
commit
1d3c48e6ce
11 changed files with 407 additions and 56 deletions
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 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.smackx.iot.provisioning;
|
||||
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public interface BecameFriendListener {
|
||||
|
||||
void becameFriend(BareJid jid, Presence presence);
|
||||
|
||||
}
|
|
@ -18,7 +18,9 @@ package org.jivesoftware.smackx.iot.provisioning;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -41,6 +43,7 @@ import org.jivesoftware.smack.packet.IQ.Type;
|
|||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.roster.AbstractPresenceEventListener;
|
||||
import org.jivesoftware.smack.roster.Roster;
|
||||
import org.jivesoftware.smack.roster.RosterEntry;
|
||||
import org.jivesoftware.smack.roster.SubscribeListener;
|
||||
|
@ -50,6 +53,7 @@ import org.jivesoftware.smackx.iot.discovery.IoTDiscoveryManager;
|
|||
import org.jivesoftware.smackx.iot.provisioning.element.ClearCache;
|
||||
import org.jivesoftware.smackx.iot.provisioning.element.ClearCacheResponse;
|
||||
import org.jivesoftware.smackx.iot.provisioning.element.Constants;
|
||||
import org.jivesoftware.smackx.iot.provisioning.element.Friend;
|
||||
import org.jivesoftware.smackx.iot.provisioning.element.IoTIsFriend;
|
||||
import org.jivesoftware.smackx.iot.provisioning.element.IoTIsFriendResponse;
|
||||
import org.jivesoftware.smackx.iot.provisioning.element.Unfriend;
|
||||
|
@ -68,6 +72,8 @@ public final class IoTProvisioningManager extends Manager {
|
|||
|
||||
private static final Logger LOGGER = Logger.getLogger(IoTProvisioningManager.class.getName());
|
||||
|
||||
private static final StanzaFilter FRIEND_MESSAGE = new AndFilter(StanzaTypeFilter.MESSAGE,
|
||||
new StanzaExtensionFilter(Friend.ELEMENT, Friend.NAMESPACE));
|
||||
private static final StanzaFilter UNFRIEND_MESSAGE = new AndFilter(StanzaTypeFilter.MESSAGE,
|
||||
new StanzaExtensionFilter(Unfriend.ELEMENT, Unfriend.NAMESPACE));
|
||||
|
||||
|
@ -99,6 +105,13 @@ public final class IoTProvisioningManager extends Manager {
|
|||
|
||||
private final Roster roster;
|
||||
private final LruCache<Jid, LruCache<BareJid, Void>> negativeFriendshipRequestCache = new LruCache<>(8);
|
||||
private final LruCache<BareJid, Void> friendshipDeniedCache = new LruCache<>(16);
|
||||
|
||||
private final LruCache<BareJid, Void> friendshipRequestedCache = new LruCache<>(16);
|
||||
|
||||
private final Set<BecameFriendListener> becameFriendListeners = new CopyOnWriteArraySet<>();
|
||||
|
||||
private final Set<WasUnfriendedListener> wasUnfriendedListeners = new CopyOnWriteArraySet<>();
|
||||
|
||||
private Jid configuredProvisioningServer;
|
||||
|
||||
|
@ -129,6 +142,47 @@ public final class IoTProvisioningManager extends Manager {
|
|||
}
|
||||
}, UNFRIEND_MESSAGE);
|
||||
|
||||
// Stanza listener for XEP-0324 § 3.2.4.
|
||||
connection.addAsyncStanzaListener(new StanzaListener() {
|
||||
@Override
|
||||
public void processPacket(final Stanza stanza) throws NotConnectedException, InterruptedException {
|
||||
final Message friendMessage = (Message) stanza;
|
||||
final Friend friend = Friend.from(friendMessage);
|
||||
final BareJid friendJid = friend.getFriend();
|
||||
|
||||
if (isFromProvisioningService(friendMessage)) {
|
||||
// We received a recommendation from a provisioning server.
|
||||
// Notify the recommended friend that we will now accept his
|
||||
// friendship requests.
|
||||
final XMPPConnection connection = connection();
|
||||
Friend friendNotifiacation = new Friend(connection.getUser().asBareJid());
|
||||
Message notificationMessage = new Message(friendJid, friendNotifiacation);
|
||||
connection.sendStanza(notificationMessage);
|
||||
} else {
|
||||
// Check is the message was send from a thing we previously
|
||||
// tried to become friends with. If this is the case, then
|
||||
// thing is likely telling us that we can become now
|
||||
// friends.
|
||||
Jid from = friendMessage.getFrom();
|
||||
if (!friendshipDeniedCache.containsKey(from)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BareJid bareFrom = from.asBareJid();
|
||||
// Sanity check: If a thing recommends us itself as friend,
|
||||
// which should be the case once we reach this code, then
|
||||
// the bare 'from' JID should be equals to the JID of the
|
||||
// recommended friend.
|
||||
if (!bareFrom.equals(friendJid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-try the friendship request.
|
||||
sendFriendshipRequest(friendJid);
|
||||
}
|
||||
}
|
||||
}, FRIEND_MESSAGE);
|
||||
|
||||
connection.registerIQRequestHandler(
|
||||
new AbstractIqRequestHandler(ClearCache.ELEMENT, ClearCache.NAMESPACE, Type.set, Mode.async) {
|
||||
@Override
|
||||
|
@ -193,6 +247,25 @@ public final class IoTProvisioningManager extends Manager {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
roster.addPresenceEventListener(new AbstractPresenceEventListener() {
|
||||
@Override
|
||||
public void presenceSubscribed(BareJid address, Presence subscribedPresence) {
|
||||
friendshipRequestedCache.remove(address);
|
||||
for (BecameFriendListener becameFriendListener : becameFriendListeners) {
|
||||
becameFriendListener.becameFriend(address, subscribedPresence);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void presenceUnsubscribed(BareJid address, Presence unsubscribedPresence) {
|
||||
if (friendshipRequestedCache.containsKey(address)) {
|
||||
friendshipDeniedCache.put(address, null);
|
||||
}
|
||||
for (WasUnfriendedListener wasUnfriendedListener : wasUnfriendedListeners) {
|
||||
wasUnfriendedListener.wasUnfriendedListener(address, unsubscribedPresence);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,6 +345,9 @@ public final class IoTProvisioningManager extends Manager {
|
|||
public void sendFriendshipRequest(BareJid bareJid) throws NotConnectedException, InterruptedException {
|
||||
Presence presence = new Presence(Presence.Type.subscribe);
|
||||
presence.setTo(bareJid);
|
||||
|
||||
friendshipRequestedCache.put(bareJid, null);
|
||||
|
||||
connection().sendStanza(presence);
|
||||
}
|
||||
|
||||
|
@ -295,6 +371,22 @@ public final class IoTProvisioningManager extends Manager {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean addBecameFriendListener(BecameFriendListener becameFriendListener) {
|
||||
return becameFriendListeners.add(becameFriendListener);
|
||||
}
|
||||
|
||||
public boolean removeBecameFriendListener(BecameFriendListener becameFriendListener) {
|
||||
return becameFriendListeners.remove(becameFriendListener);
|
||||
}
|
||||
|
||||
public boolean addWasUnfriendedListener(WasUnfriendedListener wasUnfriendedListener) {
|
||||
return wasUnfriendedListeners.add(wasUnfriendedListener);
|
||||
}
|
||||
|
||||
public boolean removeWasUnfriendedListener(WasUnfriendedListener wasUnfriendedListener) {
|
||||
return wasUnfriendedListeners.remove(wasUnfriendedListener);
|
||||
}
|
||||
|
||||
private boolean isFromProvisioningService(Stanza stanza) {
|
||||
Jid provisioningServer;
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 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.smackx.iot.provisioning;
|
||||
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public interface WasUnfriendedListener {
|
||||
|
||||
void wasUnfriendedListener(BareJid jid, Presence presence);
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2016 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.smackx.iot.provisioning.element;
|
||||
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
public class Friend implements ExtensionElement {
|
||||
|
||||
public static final String ELEMENT = "friend";
|
||||
public static final String NAMESPACE = Constants.IOT_PROVISIONING_NAMESPACE;
|
||||
|
||||
private final BareJid friend;
|
||||
|
||||
public Friend(BareJid friend) {
|
||||
this.friend = Objects.requireNonNull(friend, "Friend must not be null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElementName() {
|
||||
return ELEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlStringBuilder toXML() {
|
||||
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||
xml.attribute("jid", friend);
|
||||
xml.closeEmptyElement();
|
||||
return xml;
|
||||
}
|
||||
|
||||
public BareJid getFriend() {
|
||||
return friend;
|
||||
}
|
||||
|
||||
public static Friend from(Message message) {
|
||||
return message.getExtension(ELEMENT, NAMESPACE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
*
|
||||
* Copyright © 2016 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.smackx.iot.provisioning.provider;
|
||||
|
||||
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||
import org.jivesoftware.smack.util.ParserUtils;
|
||||
import org.jivesoftware.smackx.iot.provisioning.element.Friend;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public class FriendProvider extends ExtensionElementProvider<Friend> {
|
||||
|
||||
@Override
|
||||
public Friend parse(XmlPullParser parser, int initialDepth) throws XmppStringprepException {
|
||||
BareJid jid = ParserUtils.getBareJidAttribute(parser);
|
||||
return new Friend(jid);
|
||||
}
|
||||
|
||||
}
|
|
@ -132,6 +132,11 @@
|
|||
<namespace>urn:xmpp:iot:provisioning</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.provisioning.provider.ClearCacheResponseProvider</className>
|
||||
</iqProvider>
|
||||
<extensionProvider>
|
||||
<elementName>friend</elementName>
|
||||
<namespace>urn:xmpp:iot:provisioning</namespace>
|
||||
<className>org.jivesoftware.smackx.iot.provisioning.provider.FriendProvider</className>
|
||||
</extensionProvider>
|
||||
<extensionProvider>
|
||||
<elementName>unfriend</elementName>
|
||||
<namespace>urn:xmpp:iot:provisioning</namespace>
|
||||
|
|
|
@ -681,6 +681,7 @@ public final class Roster extends Manager {
|
|||
Objects.requireNonNull(subscribeListener, "SubscribeListener argument must not be null");
|
||||
if (subscriptionMode != SubscriptionMode.manual) {
|
||||
previousSubscriptionMode = subscriptionMode;
|
||||
subscriptionMode = SubscriptionMode.manual;
|
||||
}
|
||||
return subscribeListeners.add(subscribeListener);
|
||||
}
|
||||
|
@ -1228,6 +1229,7 @@ public final class Roster extends Manager {
|
|||
RosterPacket.Item oldItem = RosterEntry.toRosterItem(oldEntry);
|
||||
if (!oldEntry.equalsDeep(entry) || !item.getGroupNames().equals(oldItem.getGroupNames())) {
|
||||
updatedEntries.add(item.getJid());
|
||||
oldEntry.updateItem(item);
|
||||
} else {
|
||||
// Record the entry as unchanged, so that it doesn't end up as deleted entry
|
||||
unchangedEntries.add(item.getJid());
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.jivesoftware.smack.XMPPConnection;
|
|||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.packet.Presence.Type;
|
||||
import org.jivesoftware.smack.roster.packet.RosterPacket;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
|
||||
|
@ -41,7 +43,7 @@ import org.jxmpp.jid.BareJid;
|
|||
*/
|
||||
public final class RosterEntry extends Manager {
|
||||
|
||||
private final RosterPacket.Item item;
|
||||
private RosterPacket.Item item;
|
||||
final private Roster roster;
|
||||
|
||||
/**
|
||||
|
@ -120,10 +122,9 @@ public final class RosterEntry extends Manager {
|
|||
* @param type the subscription type.
|
||||
* @param subscriptionPending TODO
|
||||
*/
|
||||
void updateState(String name, RosterPacket.ItemType type, boolean subscriptionPending) {
|
||||
item.setName(name);
|
||||
item.setItemType(type);
|
||||
item.setSubscriptionPending(subscriptionPending);
|
||||
void updateItem(RosterPacket.Item item) {
|
||||
assert(item != null);
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,6 +210,18 @@ public final class RosterEntry extends Manager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the presence subscription the XMPP entity representing this roster entry has with us.
|
||||
*
|
||||
* @throws NotConnectedException
|
||||
* @throws InterruptedException
|
||||
* @since 4.2
|
||||
*/
|
||||
public void cancelSubscription() throws NotConnectedException, InterruptedException {
|
||||
Presence unsubscribed = new Presence(item.getJid(), Type.unsubscribed);
|
||||
connection().sendStanza(unsubscribed);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if (getName() != null) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.SmackException.NotLoggedInException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
|
@ -90,4 +91,24 @@ public class RosterUtil {
|
|||
roster.sendSubscriptionRequest(jid);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureNotSubscribedToEachOther(XMPPConnection connectionOne, XMPPConnection connectionTwo)
|
||||
throws NotConnectedException, InterruptedException {
|
||||
final Roster rosterOne = Roster.getInstanceFor(connectionOne);
|
||||
final BareJid jidOne = connectionOne.getUser().asBareJid();
|
||||
final Roster rosterTwo = Roster.getInstanceFor(connectionTwo);
|
||||
final BareJid jidTwo = connectionTwo.getUser().asBareJid();
|
||||
|
||||
ensureNotSubscribed(rosterOne, jidTwo);
|
||||
ensureNotSubscribed(rosterTwo, jidOne);
|
||||
}
|
||||
|
||||
public static void ensureNotSubscribed(Roster roster, BareJid jid)
|
||||
throws NotConnectedException, InterruptedException {
|
||||
RosterEntry entry = roster.getEntry(jid);
|
||||
if (entry != null && entry.canSeeMyPresence()) {
|
||||
entry.cancelSubscription();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -108,6 +108,7 @@ public class RosterPacket extends IQ {
|
|||
* A roster item, which consists of a JID, their name, the type of subscription, and
|
||||
* the groups the roster item belongs to.
|
||||
*/
|
||||
// TODO Make this class immutable.
|
||||
public static class Item implements NamedElement {
|
||||
|
||||
/**
|
||||
|
@ -124,6 +125,7 @@ public class RosterPacket extends IQ {
|
|||
*/
|
||||
private boolean subscriptionPending;
|
||||
|
||||
// TODO Make immutable.
|
||||
private String name;
|
||||
private ItemType itemType = ItemType.none;
|
||||
private boolean approved;
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
package org.igniterealtime.smack.smackrepl;
|
||||
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.roster.Roster;
|
||||
import org.jivesoftware.smack.roster.RosterUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
@ -41,6 +43,7 @@ import org.jivesoftware.smackx.iot.data.element.IoTFieldsExtension;
|
|||
import org.jivesoftware.smackx.iot.discovery.AbstractThingStateChangeListener;
|
||||
import org.jivesoftware.smackx.iot.discovery.IoTDiscoveryManager;
|
||||
import org.jivesoftware.smackx.iot.discovery.ThingState;
|
||||
import org.jivesoftware.smackx.iot.provisioning.BecameFriendListener;
|
||||
import org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
|
@ -51,24 +54,23 @@ public class IoT {
|
|||
// A 10 minute timeout.
|
||||
private static final long TIMEOUT = 10 * 60 * 1000;
|
||||
|
||||
private interface IotScenario {
|
||||
void iotScenario(XMPPTCPConnection dataThingConnection, XMPPTCPConnection readinThingConnection) throws XMPPException, SmackException, IOException, InterruptedException, TimeoutException, Exception;
|
||||
}
|
||||
|
||||
public static void iotScenario(String dataThingJidString, String dataThingPassword, String readingThingJidString,
|
||||
String readingThingPassword)
|
||||
throws TimeoutException, Exception {
|
||||
String readingThingPassword, IotScenario scenario) throws TimeoutException, Exception {
|
||||
final EntityBareJid dataThingJid = JidCreate.entityBareFrom(dataThingJidString);
|
||||
final EntityBareJid readingThingJid = JidCreate.entityBareFrom(readingThingJidString);
|
||||
|
||||
final XMPPTCPConnectionConfiguration dataThingConnectionConfiguration = XMPPTCPConnectionConfiguration.builder()
|
||||
.setUsernameAndPassword(dataThingJid.getLocalpart(), dataThingPassword)
|
||||
.setXmppDomain(dataThingJid.asDomainBareJid())
|
||||
.setSecurityMode(SecurityMode.disabled)
|
||||
.setDebuggerEnabled(true)
|
||||
.build();
|
||||
final XMPPTCPConnectionConfiguration readingThingConnectionConfiguration = XMPPTCPConnectionConfiguration.builder()
|
||||
.setUsernameAndPassword(readingThingJid.getLocalpart(), readingThingPassword)
|
||||
.setXmppDomain(readingThingJid.asDomainBareJid())
|
||||
.setSecurityMode(SecurityMode.disabled)
|
||||
.setDebuggerEnabled(true)
|
||||
.build();
|
||||
.setUsernameAndPassword(dataThingJid.getLocalpart(), dataThingPassword)
|
||||
.setXmppDomain(dataThingJid.asDomainBareJid()).setSecurityMode(SecurityMode.disabled)
|
||||
.setDebuggerEnabled(true).build();
|
||||
final XMPPTCPConnectionConfiguration readingThingConnectionConfiguration = XMPPTCPConnectionConfiguration
|
||||
.builder().setUsernameAndPassword(readingThingJid.getLocalpart(), readingThingPassword)
|
||||
.setXmppDomain(readingThingJid.asDomainBareJid()).setSecurityMode(SecurityMode.disabled)
|
||||
.setDebuggerEnabled(true).build();
|
||||
|
||||
final XMPPTCPConnection dataThingConnection = new XMPPTCPConnection(dataThingConnectionConfiguration);
|
||||
final XMPPTCPConnection readingThingConnection = new XMPPTCPConnection(readingThingConnectionConfiguration);
|
||||
|
@ -76,57 +78,123 @@ public class IoT {
|
|||
dataThingConnection.setPacketReplyTimeout(TIMEOUT);
|
||||
readingThingConnection.setPacketReplyTimeout(TIMEOUT);
|
||||
|
||||
dataThingConnection.setUseStreamManagement(false);
|
||||
readingThingConnection.setUseStreamManagement(false);
|
||||
|
||||
try {
|
||||
iotScenario(dataThingConnection, readingThingConnection);
|
||||
}
|
||||
finally {
|
||||
dataThingConnection.connect().login();
|
||||
readingThingConnection.connect().login();
|
||||
scenario.iotScenario(dataThingConnection, readingThingConnection);
|
||||
} finally {
|
||||
dataThingConnection.disconnect();
|
||||
readingThingConnection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public static void iotScenario(XMPPTCPConnection dataThingConnection, XMPPTCPConnection readingThingConnection)
|
||||
throws TimeoutException, Exception {
|
||||
dataThingConnection.connect().login();
|
||||
readingThingConnection.connect().login();
|
||||
ThingState dataThingState = actAsDataThing(dataThingConnection);
|
||||
|
||||
final SimpleResultSyncPoint syncPoint = new SimpleResultSyncPoint();
|
||||
dataThingState.setThingStateChangeListener(new AbstractThingStateChangeListener() {
|
||||
@Override
|
||||
public void owned(BareJid jid) {
|
||||
syncPoint.signal();
|
||||
}
|
||||
});
|
||||
// Wait until the thing is owned.
|
||||
syncPoint.waitForResult(TIMEOUT);
|
||||
printStatus("OWNED - Thing now onwed by " + dataThingState.getOwner());
|
||||
|
||||
// Make sure things are befriended.
|
||||
IoTProvisioningManager readingThingProvisioningManager = IoTProvisioningManager.getInstanceFor(readingThingConnection);
|
||||
readingThingProvisioningManager.sendFriendshipRequestIfRequired(dataThingConnection.getUser().asBareJid());
|
||||
|
||||
Roster dataThingRoster = Roster.getInstanceFor(dataThingConnection);
|
||||
RosterUtil.waitUntilOtherEntityIsSubscribed(dataThingRoster, readingThingConnection.getUser().asBareJid(), TIMEOUT);
|
||||
printStatus("FRIENDSHIP ACCEPTED - Trying to read out data");
|
||||
|
||||
IoTDataManager readingThingDataManager = IoTDataManager.getInstanceFor(readingThingConnection);
|
||||
List<IoTFieldsExtension> values = readingThingDataManager.requestMomentaryValuesReadOut(dataThingConnection.getUser());
|
||||
if (values.size() != 1) {
|
||||
throw new IllegalStateException("Unexpected number of values returned: " + values.size());
|
||||
}
|
||||
IoTFieldsExtension field = values.get(0);
|
||||
printStatus("DATA READ-OUT SUCCESS: " + field.toXML());
|
||||
printStatus("IoT SCENARIO FINISHED SUCCESSFULLY");
|
||||
public static void iotReadOutScenario(String dataThingJidString, String dataThingPassword, String readingThingJidString,
|
||||
String readingThingPassword)
|
||||
throws Exception {
|
||||
iotScenario(dataThingJidString, dataThingPassword, readingThingJidString, readingThingPassword, READ_OUT_SCENARIO);
|
||||
}
|
||||
|
||||
public static final IotScenario READ_OUT_SCENARIO = new IotScenario() {
|
||||
@Override
|
||||
public void iotScenario(XMPPTCPConnection dataThingConnection, XMPPTCPConnection readingThingConnection) throws TimeoutException, Exception {
|
||||
ThingState dataThingState = actAsDataThing(dataThingConnection);
|
||||
|
||||
final SimpleResultSyncPoint syncPoint = new SimpleResultSyncPoint();
|
||||
dataThingState.setThingStateChangeListener(new AbstractThingStateChangeListener() {
|
||||
@Override
|
||||
public void owned(BareJid jid) {
|
||||
syncPoint.signal();
|
||||
}
|
||||
});
|
||||
// Wait until the thing is owned.
|
||||
syncPoint.waitForResult(TIMEOUT);
|
||||
printStatus("OWNED - Thing now onwed by " + dataThingState.getOwner());
|
||||
|
||||
// Make sure things are befriended.
|
||||
IoTProvisioningManager readingThingProvisioningManager = IoTProvisioningManager.getInstanceFor(readingThingConnection);
|
||||
readingThingProvisioningManager.sendFriendshipRequestIfRequired(dataThingConnection.getUser().asBareJid());
|
||||
|
||||
Roster dataThingRoster = Roster.getInstanceFor(dataThingConnection);
|
||||
RosterUtil.waitUntilOtherEntityIsSubscribed(dataThingRoster, readingThingConnection.getUser().asBareJid(), TIMEOUT);
|
||||
printStatus("FRIENDSHIP ACCEPTED - Trying to read out data");
|
||||
|
||||
IoTDataManager readingThingDataManager = IoTDataManager.getInstanceFor(readingThingConnection);
|
||||
List<IoTFieldsExtension> values = readingThingDataManager.requestMomentaryValuesReadOut(dataThingConnection.getUser());
|
||||
if (values.size() != 1) {
|
||||
throw new IllegalStateException("Unexpected number of values returned: " + values.size());
|
||||
}
|
||||
IoTFieldsExtension field = values.get(0);
|
||||
printStatus("DATA READ-OUT SUCCESS: " + field.toXML());
|
||||
printStatus("IoT SCENARIO FINISHED SUCCESSFULLY");
|
||||
}
|
||||
};
|
||||
|
||||
public static void iotOwnerApprovesFriendScenario(String dataThingJidString, String dataThingPassword,
|
||||
String readingThingJidString, String readingThingPassword) throws Exception {
|
||||
iotScenario(dataThingJidString, dataThingPassword, readingThingJidString, readingThingPassword,
|
||||
OWNER_APPROVES_FRIEND_SCENARIO);
|
||||
}
|
||||
|
||||
public static final IotScenario OWNER_APPROVES_FRIEND_SCENARIO = new IotScenario() {
|
||||
@Override
|
||||
public void iotScenario(XMPPTCPConnection dataThingConnection, XMPPTCPConnection readingThingConnection) throws TimeoutException, Exception {
|
||||
// First ensure that the two XMPP entities are not already subscribed to each other presences.
|
||||
RosterUtil.ensureNotSubscribedToEachOther(dataThingConnection, readingThingConnection);
|
||||
|
||||
final BareJid dataThingBareJid = dataThingConnection.getUser().asBareJid();
|
||||
final BareJid readingThingBareJid = readingThingConnection.getUser().asBareJid();
|
||||
final ThingState dataThingState = actAsDataThing(dataThingConnection);
|
||||
|
||||
printStatus("WAITING for 'claimed' notification. Please claim thing now");
|
||||
final SimpleResultSyncPoint syncPoint = new SimpleResultSyncPoint();
|
||||
dataThingState.setThingStateChangeListener(new AbstractThingStateChangeListener() {
|
||||
@Override
|
||||
public void owned(BareJid jid) {
|
||||
syncPoint.signal();
|
||||
}
|
||||
});
|
||||
// Wait until the thing is owned.
|
||||
syncPoint.waitForResult(TIMEOUT);
|
||||
printStatus("OWNED - Thing now onwed by " + dataThingState.getOwner());
|
||||
|
||||
// Now, ReadingThing sends a friendship request to data thing, which
|
||||
// will proxy the request to its provisioning service, which will
|
||||
// likely return that both a not friends since the owner did not
|
||||
// authorize the friendship yet.
|
||||
final SimpleResultSyncPoint friendshipApprovedSyncPoint = new SimpleResultSyncPoint();
|
||||
final IoTProvisioningManager readingThingProvisioningManager = IoTProvisioningManager.getInstanceFor(readingThingConnection);
|
||||
final BecameFriendListener becameFriendListener = new BecameFriendListener() {
|
||||
@Override
|
||||
public void becameFriend(BareJid jid, Presence presence) {
|
||||
if (jid.equals(dataThingBareJid)) {
|
||||
friendshipApprovedSyncPoint.signal();
|
||||
}
|
||||
}
|
||||
};
|
||||
readingThingProvisioningManager.addBecameFriendListener(becameFriendListener);
|
||||
|
||||
try {
|
||||
readingThingProvisioningManager
|
||||
.sendFriendshipRequestIfRequired(dataThingConnection.getUser().asBareJid());
|
||||
friendshipApprovedSyncPoint.waitForResult(TIMEOUT);
|
||||
} finally {
|
||||
readingThingProvisioningManager.removeBecameFriendListener(becameFriendListener);
|
||||
}
|
||||
|
||||
printStatus("FRIENDSHIP APPROVED - ReadingThing " + readingThingBareJid + " is now a friend of DataThing " + dataThingBareJid);
|
||||
}
|
||||
};
|
||||
|
||||
private static ThingState actAsDataThing(XMPPTCPConnection connection) throws XMPPException, SmackException, InterruptedException {
|
||||
final String key = StringUtils.randomString(12);
|
||||
final String sn = StringUtils.randomString(12);
|
||||
Thing dataThing = Thing.builder()
|
||||
.setKey(key)
|
||||
.setSerialNumber(sn)
|
||||
.setManufacturer("Ignite Realtime")
|
||||
.setManufacturer("IgniteRealtime")
|
||||
.setModel("Smack")
|
||||
.setVersion("0.1")
|
||||
.setMomentaryReadOutRequestHandler(new ThingMomentaryReadOutRequest() {
|
||||
|
@ -153,6 +221,7 @@ public class IoT {
|
|||
if (args.length != 4) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
iotScenario(args[0], args[1], args[2], args[3]);
|
||||
iotOwnerApprovesFriendScenario(args[0], args[1], args[2], args[3]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue