IoT.java

  1. /**
  2.  *
  3.  * Copyright 2016 Florian Schmaus
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.igniterealtime.smack.smackrepl;

  18. import java.util.Collections;
  19. import java.util.List;
  20. import java.util.concurrent.TimeoutException;

  21. import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
  22. import org.jivesoftware.smack.SmackException;
  23. import org.jivesoftware.smack.XMPPException;
  24. import org.jivesoftware.smack.packet.Presence;
  25. import org.jivesoftware.smack.roster.Roster;
  26. import org.jivesoftware.smack.roster.RosterUtil;
  27. import org.jivesoftware.smack.tcp.XMPPTCPConnection;
  28. import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
  29. import org.jivesoftware.smack.util.StringUtils;
  30. import org.jivesoftware.smackx.iot.IoTDiscoveryIntegrationTest;
  31. import org.jivesoftware.smackx.iot.Thing;
  32. import org.jivesoftware.smackx.iot.data.IoTDataManager;
  33. import org.jivesoftware.smackx.iot.data.ThingMomentaryReadOutRequest;
  34. import org.jivesoftware.smackx.iot.data.ThingMomentaryReadOutResult;
  35. import org.jivesoftware.smackx.iot.data.element.IoTDataField;
  36. import org.jivesoftware.smackx.iot.data.element.IoTDataField.IntField;
  37. import org.jivesoftware.smackx.iot.data.element.IoTFieldsExtension;
  38. import org.jivesoftware.smackx.iot.discovery.AbstractThingStateChangeListener;
  39. import org.jivesoftware.smackx.iot.discovery.IoTDiscoveryManager;
  40. import org.jivesoftware.smackx.iot.discovery.ThingState;
  41. import org.jivesoftware.smackx.iot.provisioning.BecameFriendListener;
  42. import org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager;

  43. import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint;
  44. import org.jxmpp.jid.BareJid;
  45. import org.jxmpp.jid.EntityBareJid;
  46. import org.jxmpp.jid.impl.JidCreate;

  47. public class IoT {

  48.     // A 10 minute timeout.
  49.     private static final long TIMEOUT = 10 * 60 * 1000;

  50.     private interface IotScenario {
  51.         void iotScenario(XMPPTCPConnection dataThingConnection, XMPPTCPConnection readingThingConnection) throws Exception;
  52.     }

  53.     public static void iotScenario(String dataThingJidString, String dataThingPassword, String readingThingJidString,
  54.             String readingThingPassword, IotScenario scenario) throws Exception {
  55.         final EntityBareJid dataThingJid = JidCreate.entityBareFrom(dataThingJidString);
  56.         final EntityBareJid readingThingJid = JidCreate.entityBareFrom(readingThingJidString);

  57.         final XMPPTCPConnectionConfiguration dataThingConnectionConfiguration = XMPPTCPConnectionConfiguration.builder()
  58.                 .setUsernameAndPassword(dataThingJid.getLocalpart(), dataThingPassword)
  59.                 .setXmppDomain(dataThingJid.asDomainBareJid()).setSecurityMode(SecurityMode.disabled)
  60.                 .enableDefaultDebugger().build();
  61.         final XMPPTCPConnectionConfiguration readingThingConnectionConfiguration = XMPPTCPConnectionConfiguration
  62.                 .builder().setUsernameAndPassword(readingThingJid.getLocalpart(), readingThingPassword)
  63.                 .setXmppDomain(readingThingJid.asDomainBareJid()).setSecurityMode(SecurityMode.disabled)
  64.                 .enableDefaultDebugger().build();

  65.         final XMPPTCPConnection dataThingConnection = new XMPPTCPConnection(dataThingConnectionConfiguration);
  66.         final XMPPTCPConnection readingThingConnection = new XMPPTCPConnection(readingThingConnectionConfiguration);

  67.         dataThingConnection.setReplyTimeout(TIMEOUT);
  68.         readingThingConnection.setReplyTimeout(TIMEOUT);

  69.         dataThingConnection.setUseStreamManagement(false);
  70.         readingThingConnection.setUseStreamManagement(false);

  71.         try {
  72.             dataThingConnection.connect().login();
  73.             readingThingConnection.connect().login();
  74.             scenario.iotScenario(dataThingConnection, readingThingConnection);
  75.         } finally {
  76.             dataThingConnection.disconnect();
  77.             readingThingConnection.disconnect();
  78.         }
  79.     }

  80.     public static void iotReadOutScenario(String dataThingJidString, String dataThingPassword, String readingThingJidString,
  81.                     String readingThingPassword)
  82.                     throws Exception {
  83.         iotScenario(dataThingJidString, dataThingPassword, readingThingJidString, readingThingPassword, READ_OUT_SCENARIO);
  84.     }

  85.     public static final IotScenario READ_OUT_SCENARIO = new IotScenario() {
  86.         @Override
  87.         public void iotScenario(XMPPTCPConnection dataThingConnection, XMPPTCPConnection readingThingConnection) throws TimeoutException, Exception {
  88.             ThingState dataThingState = actAsDataThing(dataThingConnection);

  89.             final SimpleResultSyncPoint syncPoint = new SimpleResultSyncPoint();
  90.             dataThingState.setThingStateChangeListener(new AbstractThingStateChangeListener() {
  91.                 @Override
  92.                 public void owned(BareJid jid) {
  93.                     syncPoint.signal();
  94.                 }
  95.             });
  96.             // Wait until the thing is owned.
  97.             syncPoint.waitForResult(TIMEOUT);
  98.             printStatus("OWNED - Thing now owned by " + dataThingState.getOwner());

  99.             // Make sure things are befriended.
  100.             IoTProvisioningManager readingThingProvisioningManager = IoTProvisioningManager.getInstanceFor(readingThingConnection);
  101.             readingThingProvisioningManager.sendFriendshipRequestIfRequired(dataThingConnection.getUser().asBareJid());

  102.             Roster dataThingRoster = Roster.getInstanceFor(dataThingConnection);
  103.             RosterUtil.waitUntilOtherEntityIsSubscribed(dataThingRoster, readingThingConnection.getUser().asBareJid(), TIMEOUT);
  104.             printStatus("FRIENDSHIP ACCEPTED - Trying to read out data");

  105.             IoTDataManager readingThingDataManager = IoTDataManager.getInstanceFor(readingThingConnection);
  106.             List<IoTFieldsExtension> values = readingThingDataManager.requestMomentaryValuesReadOut(dataThingConnection.getUser());
  107.             if (values.size() != 1) {
  108.                 throw new IllegalStateException("Unexpected number of values returned: " + values.size());
  109.             }
  110.             IoTFieldsExtension field = values.get(0);
  111.             printStatus("DATA READ-OUT SUCCESS: " + field.toXML(null));
  112.             printStatus("IoT SCENARIO FINISHED SUCCESSFULLY");
  113.         }
  114.     };

  115.     public static void iotOwnerApprovesFriendScenario(String dataThingJidString, String dataThingPassword,
  116.             String readingThingJidString, String readingThingPassword) throws Exception {
  117.         iotScenario(dataThingJidString, dataThingPassword, readingThingJidString, readingThingPassword,
  118.                 OWNER_APPROVES_FRIEND_SCENARIO);
  119.     }

  120.     public static final IotScenario OWNER_APPROVES_FRIEND_SCENARIO = new IotScenario() {
  121.         @Override
  122.         public void iotScenario(XMPPTCPConnection dataThingConnection, XMPPTCPConnection readingThingConnection) throws TimeoutException, Exception {
  123.             // First ensure that the two XMPP entities are not already subscribed to each other presences.
  124.             RosterUtil.ensureNotSubscribedToEachOther(dataThingConnection, readingThingConnection);

  125.             final BareJid dataThingBareJid = dataThingConnection.getUser().asBareJid();
  126.             final BareJid readingThingBareJid = readingThingConnection.getUser().asBareJid();
  127.             final ThingState dataThingState = actAsDataThing(dataThingConnection);

  128.             printStatus("WAITING for 'claimed' notification. Please claim thing now");
  129.             final SimpleResultSyncPoint syncPoint = new SimpleResultSyncPoint();
  130.             dataThingState.setThingStateChangeListener(new AbstractThingStateChangeListener() {
  131.                 @Override
  132.                 public void owned(BareJid jid) {
  133.                     syncPoint.signal();
  134.                 }
  135.             });
  136.             // Wait until the thing is owned.
  137.             syncPoint.waitForResult(TIMEOUT);
  138.             printStatus("OWNED - Thing now owned by " + dataThingState.getOwner());

  139.             // Now, ReadingThing sends a friendship request to data thing, which
  140.             // will proxy the request to its provisioning service, which will
  141.             // likely return that both a not friends since the owner did not
  142.             // authorize the friendship yet.
  143.             final SimpleResultSyncPoint friendshipApprovedSyncPoint = new SimpleResultSyncPoint();
  144.             final IoTProvisioningManager readingThingProvisioningManager = IoTProvisioningManager.getInstanceFor(readingThingConnection);
  145.             final BecameFriendListener becameFriendListener = new BecameFriendListener() {
  146.                 @Override
  147.                 public void becameFriend(BareJid jid, Presence presence) {
  148.                     if (jid.equals(dataThingBareJid)) {
  149.                         friendshipApprovedSyncPoint.signal();
  150.                     }
  151.                 }
  152.             };
  153.             readingThingProvisioningManager.addBecameFriendListener(becameFriendListener);

  154.             try {
  155.                 readingThingProvisioningManager
  156.                         .sendFriendshipRequestIfRequired(dataThingConnection.getUser().asBareJid());
  157.                 friendshipApprovedSyncPoint.waitForResult(TIMEOUT);
  158.             } finally {
  159.                 readingThingProvisioningManager.removeBecameFriendListener(becameFriendListener);
  160.             }

  161.             printStatus("FRIENDSHIP APPROVED - ReadingThing " + readingThingBareJid + " is now a friend of DataThing " + dataThingBareJid);
  162.         }
  163.     };

  164.     private static ThingState actAsDataThing(XMPPTCPConnection connection) throws XMPPException, SmackException, InterruptedException {
  165.         final String key = StringUtils.randomString(12);
  166.         final String sn = StringUtils.randomString(12);
  167.         Thing dataThing = Thing.builder()
  168.                         .setKey(key)
  169.                         .setSerialNumber(sn)
  170.                         .setManufacturer("IgniteRealtime")
  171.                         .setModel("Smack")
  172.                         .setVersion("0.1")
  173.                         .setMomentaryReadOutRequestHandler(new ThingMomentaryReadOutRequest() {
  174.             @Override
  175.             public void momentaryReadOutRequest(ThingMomentaryReadOutResult callback) {
  176.                 IoTDataField.IntField field = new IntField("timestamp", (int) (System.currentTimeMillis() / 1000));
  177.                 callback.momentaryReadOut(Collections.singletonList(field));
  178.             }
  179.         })
  180.                         .build();
  181.         IoTDiscoveryManager iotDiscoveryManager = IoTDiscoveryManager.getInstanceFor(connection);
  182.         ThingState state = IoTDiscoveryIntegrationTest.registerThing(iotDiscoveryManager, dataThing);
  183.         printStatus("SUCCESS: Thing registered:" + dataThing);
  184.         return state;
  185.     }

  186.     private static void printStatus(CharSequence status) {
  187.         // CHECKSTYLE:OFF
  188.         System.out.println(status);
  189.         // CHECKSTYLE:ON
  190.     }

  191.     public static void main(String[] args) throws Exception {
  192.         if (args.length != 4) {
  193.             throw new IllegalArgumentException();
  194.         }
  195.         iotOwnerApprovesFriendScenario(args[0], args[1], args[2], args[3]);
  196.     }

  197. }