mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 14:22:05 +01:00
Add (partial) support for IoT XEPs
That is XEP-0323, -0324, -0325, and -0347. SMACK-727.
This commit is contained in:
parent
d1fe5c2933
commit
b91978dcc4
110 changed files with 5395 additions and 40 deletions
|
@ -55,6 +55,8 @@ debug=true
|
||||||
| accountOnePassword | Password of the first XMPP account |
|
| accountOnePassword | Password of the first XMPP account |
|
||||||
| accountTwoUsername | Username of the second XMPP account |
|
| accountTwoUsername | Username of the second XMPP account |
|
||||||
| accountTwoPassword | Password of the second XMPP account |
|
| accountTwoPassword | Password of the second XMPP account |
|
||||||
|
| accountThreeUsername | Username of the third XMPP account |
|
||||||
|
| accountThreePassword | Password of the third XMPP account |
|
||||||
| debug | 'true' to enable debug output |
|
| debug | 'true' to enable debug output |
|
||||||
| enabledTests | List of enabled tests |
|
| enabledTests | List of enabled tests |
|
||||||
| disabledTests | List of disabled tests |
|
| disabledTests | List of disabled tests |
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Smack Extensions User Manual
|
smackSmack Extensions User Manual
|
||||||
============================
|
============================
|
||||||
|
|
||||||
The XMPP protocol includes a base protocol and many optional extensions
|
The XMPP protocol includes a base protocol and many optional extensions
|
||||||
|
@ -77,8 +77,12 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
|
||||||
| Name | XEP | Description |
|
| Name | XEP | Description |
|
||||||
|---------------------------------------------|----------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------|----------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
|
||||||
| Message Carbons | [XEP-0280](http://xmpp.org/extensions/xep-0280.html) | Keep all IM clients for a user engaged in a conversation, by carbon-copy outbound messages to all interested resources.
|
| Message Carbons | [XEP-0280](http://xmpp.org/extensions/xep-0280.html) | Keep all IM clients for a user engaged in a conversation, by carbon-copy outbound messages to all interested resources.
|
||||||
| [HTTP over XMPP transport](hoxt.md) | [XEP-0332](http://xmpp.org/extensions/xep-0332.html) | Allows to transport HTTP communication over XMPP peer-to-peer networks. |
|
| [Internet of Things - Sensor Data](iot.md) | [XEP-0323](http://xmpp.org/extensions/xep-0323.html) | Sensor data interchange over XMPP. |
|
||||||
|
| [Internet of Things - Provisioning](iot.md) | [XEP-0324](http://xmpp.org/extensions/xep-0324.html) | Provisioning, access rights and user priviliges for the Internet of Things. |
|
||||||
|
| [Internet of Things - Control](iot.md) | [XEP-0325](http://xmpp.org/extensions/xep-0325.html) | Describes how to control devices or actuators in an XMPP-based sensor netowrk. |
|
||||||
|
| [HTTP over XMPP transport](hoxt.md) | [XEP-0332](http://xmpp.org/extensions/xep-0332.html) | Allows to transport HTTP communication over XMPP peer-to-peer networks. |
|
||||||
| JSON Containers | [XEP-0335](http://xmpp.org/extensions/xep-0335.html) | Encapsulation of JSON data within XMPP Stanzas. |
|
| JSON Containers | [XEP-0335](http://xmpp.org/extensions/xep-0335.html) | Encapsulation of JSON data within XMPP Stanzas. |
|
||||||
|
| [Internet of Things - Discovery](iot.md) | [XEP-0347](http://xmpp.org/extensions/xep-0347.html) | Describes how Things can be installed and discovered by their owners. |
|
||||||
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
||||||
| Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. |
|
| Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. |
|
||||||
|
|
||||||
|
|
116
documentation/extensions/iot.md
Normal file
116
documentation/extensions/iot.md
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
Internet of Things (XEP-0323, -0324, -0325, -0347)
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
The Internet of Things (IoT) XEPs are an experimental open standard how XMPP can be used for IoT. They currently consists of
|
||||||
|
- XEP-0323 Sensor Data
|
||||||
|
- XEP-0324 Provisioning
|
||||||
|
- XEP-0325 Control
|
||||||
|
- XEP-0326 Concentrators
|
||||||
|
- XEP-0347 Discovery
|
||||||
|
|
||||||
|
Smack only supports a subset of the functionality described by the XEPs!
|
||||||
|
|
||||||
|
Thing Builder
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The `org.jivesoftware.smackx.iot.Thing` class acts as basic entity representing a single "Thing" which can used to retrieve data from or to send control commands to. `Things` are constructed using a builder API.
|
||||||
|
|
||||||
|
|
||||||
|
Reading data from things
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
For example, we can build a Thing which provides the current temperature with
|
||||||
|
|
||||||
|
```java
|
||||||
|
Thing dataThing = Thing.builder().setKey(key).setSerialNumber(sn).setMomentaryReadOutRequestHandler(new ThingMomentaryReadOutRequest() {
|
||||||
|
@Override
|
||||||
|
public void momentaryReadOutRequest(ThingMomentaryReadOutResult callback) {
|
||||||
|
int temp = getCurrentTemperature();
|
||||||
|
IoTDataField.IntField field = new IntField("temperature", temp);
|
||||||
|
callback.momentaryReadOut(Collections.singletonList(field));
|
||||||
|
}
|
||||||
|
}).build();
|
||||||
|
```
|
||||||
|
|
||||||
|
While not strictly required, most things are identified via a key and serial number. We also build the thing with a "momentary read out request handler" which when triggered, retrieved the current temperature and reports it back to the requestor.
|
||||||
|
|
||||||
|
After the `Thing` is build, it needs to be made available so that other entities within the federated XMPP network can use it. Right now, we only intall the Thing in the `IoTDataManager`, which means the thing will act on read out requests but not be managed by a provisioning server.
|
||||||
|
|
||||||
|
```java
|
||||||
|
IoTDataManager iotDataManager = IoTDataManager.getInstanceFor(connection);
|
||||||
|
iotDataManager.installThing(thing);
|
||||||
|
```
|
||||||
|
|
||||||
|
The data can be read out also by using the `IoTDataManager`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
FullJid jid = …
|
||||||
|
List<IoTFieldsExtension> values = iotDataManager.requestMomentaryValuesReadOut(jid);
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you have to unwrap the `IoTDataField` instances from the `IoTFieldsExtension`. Note that Smack currently only supports a subset of the specified data types.
|
||||||
|
|
||||||
|
Controlling a thing
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Things can also be controlled, e.g. to turn on a light. Let's create thing which can be used to turn the light on and off.
|
||||||
|
|
||||||
|
```java
|
||||||
|
Thing controlThing = Thing.builder().setKey(key).setSerialNumber(sn).setControlRequestHandler(new ThingControlRequest() {
|
||||||
|
@Override
|
||||||
|
public void processRequest(Jid from, Collection<SetData> setData) throws XMPPErrorException {
|
||||||
|
for (final SetData data : setData) {
|
||||||
|
if (!data.getName().equals("light")) continue;
|
||||||
|
if (!(data instanceof SetBoolData)) continue;
|
||||||
|
SetBoolData boolData = (SetBoolData) data;
|
||||||
|
setLight(boolData.getBooleanValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).build();
|
||||||
|
```
|
||||||
|
|
||||||
|
No we have to install this thing into the `IoTControlManager`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
IoTControlManager iotControlManager = IoTControlManager.getInstanceFor(connection);
|
||||||
|
iotControlManager.installThing(thing);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `IoTControlManager` can also be used to control a thing:
|
||||||
|
|
||||||
|
```java
|
||||||
|
FullJid jid = …
|
||||||
|
SetData setData = new SetBoolData("light", true);
|
||||||
|
iotControlManager.setUsingIq(jid, setData);
|
||||||
|
```
|
||||||
|
|
||||||
|
Smack currently only supports a subset of the possible data types for set data.
|
||||||
|
|
||||||
|
Discovery
|
||||||
|
---------
|
||||||
|
|
||||||
|
You may wondered how a full JIDs of things can be determined. One approach is using the discovery mechanisms specified in XEP-0347. Smack provides the `IoTDiscoveryManager` as API for this.
|
||||||
|
|
||||||
|
For example, instead of just installing the previous things in the `IoTDataManager` and/or `IoTControlManager`, we could also use the `IoTDiscoveryManger` to register the thing with a registry. Doing thing also installs the thing in the `IoTDataManager` and the `IoTControlManager`.
|
||||||
|
|
||||||
|
```java
|
||||||
|
IoTDiscoveryManager iotDiscoveryManager = IoTDiscoveryManager.getInstanceFor(connection);
|
||||||
|
iotDiscovyerManager.registerThing(thing);
|
||||||
|
```
|
||||||
|
|
||||||
|
The registry will now make the thing known to a broader audience, and available for a potential owner.
|
||||||
|
|
||||||
|
The `IoTDiscoveryManager` can also be used to claim, disown, remove and unregister a thing.
|
||||||
|
|
||||||
|
Provisioning
|
||||||
|
------------
|
||||||
|
|
||||||
|
Things can usually only be used by other things if they are friends. Since a thing normally can't decide on its own if an incoming friendship request should be granted or not, we can delegate this decission to a provisioning service. Smack provides the `IoTProvisinoManager` to deal with friendship and provisioning.
|
||||||
|
|
||||||
|
For example, if you want to befriend another thing:
|
||||||
|
|
||||||
|
```java
|
||||||
|
BareJid jid = …
|
||||||
|
IoTProvisioningManager iotProvisioningManager = IoTProvisioningManager.getInstanceFor(connection);
|
||||||
|
iotProvisioningManager.sendFriendshipRequest(jid);
|
||||||
|
```
|
|
@ -238,7 +238,11 @@ public final class ReconnectionManager {
|
||||||
// Makes a reconnection attempt
|
// Makes a reconnection attempt
|
||||||
try {
|
try {
|
||||||
if (isReconnectionPossible(connection)) {
|
if (isReconnectionPossible(connection)) {
|
||||||
connection.connect();
|
try {
|
||||||
|
connection.connect();
|
||||||
|
} catch (SmackException.AlreadyConnectedException e) {
|
||||||
|
LOGGER.log(Level.FINER, "Connection was already connected on reconnection attempt", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO Starting with Smack 4.2, connect() will no
|
// TODO Starting with Smack 4.2, connect() will no
|
||||||
// longer login automatically. So change this and the
|
// longer login automatically. So change this and the
|
||||||
|
|
|
@ -25,13 +25,7 @@ public class EmptyResultIQ extends IQ {
|
||||||
|
|
||||||
public EmptyResultIQ(IQ request) {
|
public EmptyResultIQ(IQ request) {
|
||||||
this();
|
this();
|
||||||
if (!(request.getType() == Type.get || request.getType() == Type.set)) {
|
initialzeAsResultFor(request);
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
|
|
||||||
}
|
|
||||||
setStanzaId(request.getStanzaId());
|
|
||||||
setFrom(request.getTo());
|
|
||||||
setTo(request.getFrom());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -215,6 +215,17 @@ public abstract class IQ extends Stanza {
|
||||||
*/
|
*/
|
||||||
protected abstract IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml);
|
protected abstract IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml);
|
||||||
|
|
||||||
|
protected final void initialzeAsResultFor(IQ request) {
|
||||||
|
if (!(request.getType() == Type.get || request.getType() == Type.set)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
|
||||||
|
}
|
||||||
|
setStanzaId(request.getStanzaId());
|
||||||
|
setFrom(request.getTo());
|
||||||
|
setTo(request.getFrom());
|
||||||
|
setType(Type.result);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method to create a new empty {@link Type#result IQ.Type.result}
|
* Convenience method to create a new empty {@link Type#result IQ.Type.result}
|
||||||
* IQ based on a {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}
|
* IQ based on a {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}
|
||||||
|
@ -289,9 +300,7 @@ public abstract class IQ extends Stanza {
|
||||||
* @throws IllegalArgumentException if the IQ stanza(/packet) does not have a type of
|
* @throws IllegalArgumentException if the IQ stanza(/packet) does not have a type of
|
||||||
* {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}.
|
* {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}.
|
||||||
* @return a new {@link Type#error IQ.Type.error} IQ based on the originating IQ.
|
* @return a new {@link Type#error IQ.Type.error} IQ based on the originating IQ.
|
||||||
* @deprecated use {@link #createErrorResponse(IQ, org.jivesoftware.smack.packet.XMPPError.Builder)} instead.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static ErrorIQ createErrorResponse(final IQ request, final XMPPError error) {
|
public static ErrorIQ createErrorResponse(final IQ request, final XMPPError error) {
|
||||||
return createErrorResponse(request, XMPPError.getBuilder(error));
|
return createErrorResponse(request, XMPPError.getBuilder(error));
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,8 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* @param type the type.
|
* @param type the type.
|
||||||
*/
|
*/
|
||||||
public Presence(Type type) {
|
public Presence(Type type) {
|
||||||
|
// Ensure that the stanza ID is set by calling super().
|
||||||
|
super();
|
||||||
setType(type);
|
setType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +87,8 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
|
||||||
* @param mode the mode type for this presence update.
|
* @param mode the mode type for this presence update.
|
||||||
*/
|
*/
|
||||||
public Presence(Type type, String status, int priority, Mode mode) {
|
public Presence(Type type, String status, int priority, Mode mode) {
|
||||||
|
// Ensure that the stanza ID is set by calling super().
|
||||||
|
super();
|
||||||
setType(type);
|
setType(type);
|
||||||
setStatus(status);
|
setStatus(status);
|
||||||
setPriority(priority);
|
setPriority(priority);
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.text.ParseException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jxmpp.jid.EntityBareJid;
|
import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
|
@ -122,6 +123,14 @@ public class ParserUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getIntegerAttributeOrThrow(XmlPullParser parser, String name, String throwMessage) throws SmackException {
|
||||||
|
Integer res = getIntegerAttribute(parser, name);
|
||||||
|
if (res == null) {
|
||||||
|
throw new SmackException(throwMessage);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
public static Integer getIntegerAttribute(XmlPullParser parser, String name) {
|
public static Integer getIntegerAttribute(XmlPullParser parser, String name) {
|
||||||
String valueString = parser.getAttributeValue("", name);
|
String valueString = parser.getAttributeValue("", name);
|
||||||
if (valueString == null)
|
if (valueString == null)
|
||||||
|
|
|
@ -238,6 +238,10 @@ public class XmlStringBuilder implements Appendable, CharSequence {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public XmlStringBuilder attribute(String name, boolean bool) {
|
||||||
|
return attribute(name, Boolean.toString(bool));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new attribute to this builder, with the {@link java.util.Date} instance as its value,
|
* Add a new attribute to this builder, with the {@link java.util.Date} instance as its value,
|
||||||
* which will get formated with {@link XmppDateTime#formatXEP0082Date(Date)}.
|
* which will get formated with {@link XmppDateTime#formatXEP0082Date(Date)}.
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
|
||||||
|
public class IoTException extends SmackException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
|
||||||
|
public final class IoTManager extends Manager {
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, IoTManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
public static synchronized IoTManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
IoTManager manager = INSTANCES.get(connection);
|
||||||
|
if (manager == null) {
|
||||||
|
manager = new IoTManager(connection);
|
||||||
|
INSTANCES.put(connection, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IoTManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.iot.control.ThingControlRequest;
|
||||||
|
import org.jivesoftware.smackx.iot.data.ThingMomentaryReadOutRequest;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.Tag;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.Tag.Type;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
|
||||||
|
public final class Thing {
|
||||||
|
|
||||||
|
private final HashMap<String, Tag> metaTags;
|
||||||
|
private final boolean selfOwned;
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
|
||||||
|
private final ThingMomentaryReadOutRequest momentaryReadOutRequestHandler;
|
||||||
|
private final ThingControlRequest controlRequestHandler;
|
||||||
|
|
||||||
|
private Thing(Builder builder) {
|
||||||
|
this.metaTags = builder.metaTags;
|
||||||
|
this.selfOwned = builder.selfOwned;
|
||||||
|
|
||||||
|
this.nodeInfo = builder.nodeInfo;
|
||||||
|
|
||||||
|
this.momentaryReadOutRequestHandler = builder.momentaryReadOutRequest;
|
||||||
|
this.controlRequestHandler = builder.controlRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Tag> getMetaTags() {
|
||||||
|
return metaTags.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSelfOwened() {
|
||||||
|
return selfOwned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo getNodeInfo() {
|
||||||
|
return nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeInfo.getNodeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceId() {
|
||||||
|
return nodeInfo.getSourceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCacheType() {
|
||||||
|
return nodeInfo.getCacheType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThingMomentaryReadOutRequest getMomentaryReadOutRequestHandler() {
|
||||||
|
return momentaryReadOutRequestHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThingControlRequest getControlRequestHandler() {
|
||||||
|
return controlRequestHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toStringCache;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (toStringCache == null) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append( "Thing " + nodeInfo + " [");
|
||||||
|
Iterator<Tag> it = metaTags.values().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Tag tag = it.next();
|
||||||
|
sb.append(tag);
|
||||||
|
if (it.hasNext()) {
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append(']');
|
||||||
|
toStringCache = sb.toString();
|
||||||
|
}
|
||||||
|
return toStringCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private HashMap<String, Tag> metaTags = new HashMap<>();
|
||||||
|
private boolean selfOwned;
|
||||||
|
private NodeInfo nodeInfo = NodeInfo.EMPTY;
|
||||||
|
private ThingMomentaryReadOutRequest momentaryReadOutRequest;
|
||||||
|
private ThingControlRequest controlRequest;
|
||||||
|
|
||||||
|
public Builder setSerialNumber(String sn) {
|
||||||
|
final String name = "SN";
|
||||||
|
Tag tag = new Tag(name, Type.str, sn);
|
||||||
|
metaTags.put(name, tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setKey(String key) {
|
||||||
|
final String name = "KEY";
|
||||||
|
Tag tag = new Tag(name, Type.str, key);
|
||||||
|
metaTags.put(name, tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setManufacturer(String manufacturer) {
|
||||||
|
final String name = "MAN";
|
||||||
|
Tag tag = new Tag(name, Type.str, manufacturer);
|
||||||
|
metaTags.put(name, tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setModel(String model) {
|
||||||
|
final String name = "MODEL";
|
||||||
|
Tag tag = new Tag(name, Type.str, model);
|
||||||
|
metaTags.put(name, tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setVersion(String version) {
|
||||||
|
final String name = "V";
|
||||||
|
Tag tag = new Tag(name, Type.num, version);
|
||||||
|
metaTags.put(name, tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setMomentaryReadOutRequestHandler(ThingMomentaryReadOutRequest momentaryReadOutRequestHandler) {
|
||||||
|
this.momentaryReadOutRequest = momentaryReadOutRequestHandler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setControlRequestHandler(ThingControlRequest controlRequest) {
|
||||||
|
this.controlRequest = controlRequest;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thing build() {
|
||||||
|
return new Thing(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
|
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
|
||||||
|
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.iot.Thing;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.IoTSetRequest;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.IoTSetResponse;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.SetData;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jxmpp.jid.FullJid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manger for XEP-0325: Internet of Things - Control.
|
||||||
|
*
|
||||||
|
* @author Florian Schmaus {@literal <flo@geekplace.eu>}
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0325.html">XEP-0323: Internet of Things - Control</a>
|
||||||
|
*/
|
||||||
|
public final class IoTControlManager extends Manager {
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, IoTControlManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the manger instance responsible for the given connection.
|
||||||
|
*
|
||||||
|
* @param connection the XMPP connection.
|
||||||
|
* @return a manager instance.
|
||||||
|
*/
|
||||||
|
public static synchronized IoTControlManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
IoTControlManager manager = INSTANCES.get(connection);
|
||||||
|
if (manager == null) {
|
||||||
|
manager = new IoTControlManager(connection);
|
||||||
|
INSTANCES.put(connection, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<NodeInfo, Thing> things = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private IoTControlManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
connection.registerIQRequestHandler(new AbstractIqRequestHandler(IoTSetRequest.ELEMENT, IoTSetRequest.NAMESPACE, IQ.Type.set, Mode.async) {
|
||||||
|
@Override
|
||||||
|
public IQ handleIQRequest(IQ iqRequest) {
|
||||||
|
// TODO Lookup thing and provide data.
|
||||||
|
IoTSetRequest iotSetRequest = (IoTSetRequest) iqRequest;
|
||||||
|
|
||||||
|
// TODO Add support for multiple things(/NodeInfos).
|
||||||
|
final Thing thing = things.get(NodeInfo.EMPTY);
|
||||||
|
if (thing == null) {
|
||||||
|
// TODO return error if not at least one thing registered.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThingControlRequest controlRequest = thing.getControlRequestHandler();
|
||||||
|
if (controlRequest == null) {
|
||||||
|
// TODO return error if no request handler for things.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
controlRequest.processRequest(iotSetRequest.getFrom(), iotSetRequest.getSetData());
|
||||||
|
} catch (XMPPErrorException e) {
|
||||||
|
return IQ.createErrorResponse(iotSetRequest, e.getXMPPError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IoTSetResponse(iotSetRequest);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control a thing by sending a collection of {@link SetData} instructions.
|
||||||
|
*
|
||||||
|
* @param jid
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @see #setUsingIq(FullJid, Collection)
|
||||||
|
*/
|
||||||
|
public IoTSetResponse setUsingIq(FullJid jid, SetData data) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
return setUsingIq(jid, Collections.singleton(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control a thing by sending a collection of {@link SetData} instructions.
|
||||||
|
*
|
||||||
|
* @param jid the thing to control.
|
||||||
|
* @param data a collection of {@link SetData} instructions.
|
||||||
|
* @return the {@link IoTSetResponse} if successful.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
public IoTSetResponse setUsingIq(FullJid jid, Collection<SetData> data) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
IoTSetRequest request = new IoTSetRequest(data);
|
||||||
|
request.setTo(jid);
|
||||||
|
IoTSetResponse response = connection().createPacketCollectorAndSend(request).nextResultOrThrow();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a thing in the manager. Activates control functionality (if provided by the thing).
|
||||||
|
*
|
||||||
|
* @param thing the thing to install.
|
||||||
|
*/
|
||||||
|
public void installThing(Thing thing) {
|
||||||
|
things.put(thing.getNodeInfo(), thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thing uninstallThing(Thing thing) {
|
||||||
|
return uninstallThing(thing.getNodeInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thing uninstallThing(NodeInfo nodeInfo) {
|
||||||
|
return things.remove(nodeInfo);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.SetData;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
public interface ThingControlRequest {
|
||||||
|
|
||||||
|
public void processRequest(Jid from, Collection<SetData> setData) throws XMPPErrorException;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.element;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
public static final String IOT_CONTROL_NAMESPACE = "urn:xmpp:iot:control";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.element;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
|
||||||
|
public class IoTSetRequest extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "set";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_CONTROL_NAMESPACE;
|
||||||
|
|
||||||
|
private final Collection<SetData> setData;
|
||||||
|
|
||||||
|
public IoTSetRequest(Collection<SetData> setData) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
setType(Type.set);
|
||||||
|
this.setData = Collections.unmodifiableCollection(setData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<SetData> getSetData() {
|
||||||
|
return setData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
xml.append(setData);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
|
||||||
|
public class IoTSetResponse extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "setResponse";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_CONTROL_NAMESPACE;
|
||||||
|
|
||||||
|
public IoTSetResponse() {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTSetResponse(IoTSetRequest iotSetRequest) {
|
||||||
|
this();
|
||||||
|
initialzeAsResultFor(iotSetRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.setEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.element;
|
||||||
|
|
||||||
|
public class SetBoolData extends SetData {
|
||||||
|
|
||||||
|
public SetBoolData(String name, boolean value) {
|
||||||
|
this(name, Boolean.toString(value));
|
||||||
|
booleanCache = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SetBoolData(String name, String value) {
|
||||||
|
super(name, Type.BOOL, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean booleanCache;
|
||||||
|
|
||||||
|
public Boolean getBooleanValue() {
|
||||||
|
if (booleanCache != null) {
|
||||||
|
booleanCache = Boolean.valueOf(getValue());
|
||||||
|
}
|
||||||
|
return booleanCache;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.element;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public abstract class SetData implements NamedElement {
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
BOOL,
|
||||||
|
INT,
|
||||||
|
LONG,
|
||||||
|
DOUBLE,
|
||||||
|
;
|
||||||
|
|
||||||
|
private String toStringCache;
|
||||||
|
|
||||||
|
private Type() {
|
||||||
|
toStringCache = this.name().toLowerCase(Locale.US);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toStringCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SetData(String name, Type type, String value) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final Type type;
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
public final String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the root element name.
|
||||||
|
*
|
||||||
|
* @return the element name.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final String getElementName() {
|
||||||
|
return getType().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the XML representation of this Element.
|
||||||
|
*
|
||||||
|
* @return the stanza(/packet) extension as XML.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.attribute("name", name);
|
||||||
|
xml.attribute("value", value);
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.element;
|
||||||
|
|
||||||
|
public class SetDoubleData extends SetData {
|
||||||
|
|
||||||
|
public SetDoubleData(String name, double value) {
|
||||||
|
this(name, Double.toString(value));
|
||||||
|
doubleCache = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SetDoubleData(String name, String value) {
|
||||||
|
super(name, Type.DOUBLE, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Double doubleCache;
|
||||||
|
|
||||||
|
public Double getDoubleValue() {
|
||||||
|
if (doubleCache != null) {
|
||||||
|
doubleCache = Double.valueOf(getValue());
|
||||||
|
}
|
||||||
|
return doubleCache;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.element;
|
||||||
|
|
||||||
|
public class SetIntData extends SetData {
|
||||||
|
|
||||||
|
public SetIntData(String name, int value) {
|
||||||
|
this(name, Integer.toString(value));
|
||||||
|
integerCache = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SetIntData(String name, String value) {
|
||||||
|
super(name, Type.INT, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer integerCache;
|
||||||
|
|
||||||
|
public Integer getIntegerValue() {
|
||||||
|
if (integerCache != null) {
|
||||||
|
integerCache = Integer.valueOf(getValue());
|
||||||
|
}
|
||||||
|
return integerCache;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.element;
|
||||||
|
|
||||||
|
public class SetLongData extends SetData {
|
||||||
|
|
||||||
|
public SetLongData(String name, long value) {
|
||||||
|
this(name, Long.toString(value));
|
||||||
|
longCache = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SetLongData(String name, String value) {
|
||||||
|
super(name, Type.LONG, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long longCache;
|
||||||
|
|
||||||
|
public Long getLongValue() {
|
||||||
|
if (longCache != null) {
|
||||||
|
longCache = Long.valueOf(getValue());
|
||||||
|
}
|
||||||
|
return longCache;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.control.element;
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.control;
|
|
@ -0,0 +1,82 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.provider;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.IoTSetRequest;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.SetBoolData;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.SetData;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.SetDoubleData;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.SetIntData;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.SetLongData;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTSetRequestProvider extends IQProvider<IoTSetRequest> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTSetRequest parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
List<SetData> data = new ArrayList<>(4);
|
||||||
|
outerloop: while (true) {
|
||||||
|
final int eventType = parser.next();
|
||||||
|
final String name = parser.getName();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
switch (name) {
|
||||||
|
case "bool": {
|
||||||
|
String valueName = parser.getAttributeValue(null, "name");
|
||||||
|
String valueString = parser.getAttributeValue(null, "value");
|
||||||
|
boolean value = Boolean.parseBoolean(valueString);
|
||||||
|
data.add(new SetBoolData(valueName, value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "double": {
|
||||||
|
String valueName = parser.getAttributeValue(null, "name");
|
||||||
|
String valueString = parser.getAttributeValue(null, "value");
|
||||||
|
double value = Double.parseDouble(valueString);
|
||||||
|
data.add(new SetDoubleData(valueName, value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "int": {
|
||||||
|
String valueName = parser.getAttributeValue(null, "name");
|
||||||
|
String valueString = parser.getAttributeValue(null, "value");
|
||||||
|
int value = Integer.parseInt(valueString);
|
||||||
|
data.add(new SetIntData(valueName, value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "long": {
|
||||||
|
String valueName = parser.getAttributeValue(null, "name");
|
||||||
|
String valueString = parser.getAttributeValue(null, "value");
|
||||||
|
long value = Long.parseLong(valueString);
|
||||||
|
data.add(new SetLongData(valueName, value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new IoTSetRequest(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.control.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smackx.iot.control.element.IoTSetResponse;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTSetResponseProvider extends IQProvider<IoTSetResponse> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTSetResponse parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
return new IoTSetResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.control.provider;
|
|
@ -0,0 +1,210 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.PacketCollector;
|
||||||
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPConnectionRegistry;
|
||||||
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
|
import org.jivesoftware.smack.filter.StanzaFilter;
|
||||||
|
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
|
||||||
|
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smackx.iot.Thing;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTDataField;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTDataReadOutAccepted;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTDataRequest;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTFieldsExtension;
|
||||||
|
import org.jivesoftware.smackx.iot.data.filter.IoTFieldsExtensionFilter;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manager for XEP-0323: Internet of Things - Sensor Data.
|
||||||
|
*
|
||||||
|
* @author Florian Schmaus {@literal <flo@geekplace.eu>}
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0323.html">XEP-0323: Internet of Things - Sensor Data</a>
|
||||||
|
*/
|
||||||
|
public final class IoTDataManager extends Manager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(IoTDataManager.class.getName());
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, IoTDataManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
// Ensure a IoTDataManager exists for every connection.
|
||||||
|
static {
|
||||||
|
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
|
public void connectionCreated(XMPPConnection connection) {
|
||||||
|
getInstanceFor(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the manger instance responsible for the given connection.
|
||||||
|
*
|
||||||
|
* @param connection the XMPP connection.
|
||||||
|
* @return a manager instance.
|
||||||
|
*/
|
||||||
|
public static synchronized IoTDataManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
IoTDataManager manager = INSTANCES.get(connection);
|
||||||
|
if (manager == null) {
|
||||||
|
manager = new IoTDataManager(connection);
|
||||||
|
INSTANCES.put(connection, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final AtomicInteger nextSeqNr = new AtomicInteger();
|
||||||
|
|
||||||
|
private final Map<NodeInfo, Thing> things = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private IoTDataManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
|
||||||
|
connection.registerIQRequestHandler(new AbstractIqRequestHandler(IoTDataRequest.ELEMENT,
|
||||||
|
IoTDataRequest.NAMESPACE, IQ.Type.get, Mode.async) {
|
||||||
|
@Override
|
||||||
|
public IQ handleIQRequest(IQ iqRequest) {
|
||||||
|
// TODO Verify that iqRequest.from is friend?
|
||||||
|
|
||||||
|
final IoTDataRequest dataRequest = (IoTDataRequest) iqRequest;
|
||||||
|
|
||||||
|
if (!dataRequest.isMomentary()) {
|
||||||
|
// TODO return error IQ that non momentary requests are not implemented yet.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Add support for multiple things(/NodeInfos).
|
||||||
|
final Thing thing = things.get(NodeInfo.EMPTY);
|
||||||
|
if (thing == null) {
|
||||||
|
// TODO return error if not at least one thing registered.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThingMomentaryReadOutRequest readOutRequest = thing.getMomentaryReadOutRequestHandler();
|
||||||
|
if (readOutRequest == null) {
|
||||||
|
// TODO Thing does not provide momentary read-out
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback hell begins here. :) XEP-0323 decouples the read-out results from the IQ result. I'm not
|
||||||
|
// sure if I would have made the same design decision but the reasons where likely being able to get a
|
||||||
|
// fast read-out acknowledgement back to the requester even with sensors that take "a long time" to
|
||||||
|
// read-out their values. I had designed that as special case and made the "results in IQ response" the
|
||||||
|
// normal case.
|
||||||
|
readOutRequest.momentaryReadOutRequest(new ThingMomentaryReadOutResult() {
|
||||||
|
@Override
|
||||||
|
public void momentaryReadOut(List<? extends IoTDataField> results) {
|
||||||
|
IoTFieldsExtension iotFieldsExtension = IoTFieldsExtension.buildFor(dataRequest.getSequenceNr(), true, thing.getNodeInfo(), results);
|
||||||
|
Message message = new Message(dataRequest.getFrom());
|
||||||
|
message.addExtension(iotFieldsExtension);
|
||||||
|
try {
|
||||||
|
connection().sendStanza(message);
|
||||||
|
}
|
||||||
|
catch (NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Could not send read-out response " + message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new IoTDataReadOutAccepted(dataRequest);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a thing in the manager. Activates data read out functionality (if provided by the
|
||||||
|
* thing).
|
||||||
|
*
|
||||||
|
* @param thing the thing to install.
|
||||||
|
*/
|
||||||
|
public void installThing(Thing thing) {
|
||||||
|
things.put(thing.getNodeInfo(), thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thing uninstallThing(Thing thing) {
|
||||||
|
return uninstallThing(thing.getNodeInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thing uninstallThing(NodeInfo nodeInfo) {
|
||||||
|
return things.remove(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to read out a things momentary values.
|
||||||
|
*
|
||||||
|
* @param jid the full JID of the thing to read data from.
|
||||||
|
* @return a list with the read out data.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
public List<IoTFieldsExtension> requestMomentaryValuesReadOut(EntityFullJid jid)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
final XMPPConnection connection = connection();
|
||||||
|
final int seqNr = nextSeqNr.incrementAndGet();
|
||||||
|
IoTDataRequest iotDataRequest = new IoTDataRequest(seqNr, true);
|
||||||
|
iotDataRequest.setTo(jid);
|
||||||
|
|
||||||
|
StanzaFilter doneFilter = new IoTFieldsExtensionFilter(seqNr, true);
|
||||||
|
StanzaFilter dataFilter = new IoTFieldsExtensionFilter(seqNr, false);
|
||||||
|
|
||||||
|
// Setup the IoTFieldsExtension message collectors before sending the IQ to avoid a data race.
|
||||||
|
PacketCollector doneCollector = connection.createPacketCollector(doneFilter);
|
||||||
|
|
||||||
|
PacketCollector.Configuration dataCollectorConfiguration = PacketCollector.newConfiguration().setStanzaFilter(
|
||||||
|
dataFilter).setCollectorToReset(doneCollector);
|
||||||
|
PacketCollector dataCollector = connection.createPacketCollector(dataCollectorConfiguration);
|
||||||
|
|
||||||
|
try {
|
||||||
|
connection.createPacketCollectorAndSend(iotDataRequest).nextResultOrThrow();
|
||||||
|
// Wait until a message with an IoTFieldsExtension and the done flag comes in.
|
||||||
|
doneCollector.nextResult();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// Ensure that the two collectors are canceled in any case.
|
||||||
|
dataCollector.cancel();
|
||||||
|
doneCollector.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int collectedCount = dataCollector.getCollectedCount();
|
||||||
|
List<IoTFieldsExtension> res = new ArrayList<>(collectedCount);
|
||||||
|
for (int i = 0; i < collectedCount; i++) {
|
||||||
|
Message message = dataCollector.pollResult();
|
||||||
|
IoTFieldsExtension iotFieldsExtension = IoTFieldsExtension.from(message);
|
||||||
|
res.add(iotFieldsExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data;
|
||||||
|
|
||||||
|
public interface ThingMomentaryReadOutRequest {
|
||||||
|
|
||||||
|
public void momentaryReadOutRequest(ThingMomentaryReadOutResult callback);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTDataField;
|
||||||
|
|
||||||
|
public interface ThingMomentaryReadOutResult {
|
||||||
|
|
||||||
|
public void momentaryReadOut(List<? extends IoTDataField> results);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.element;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
public static final String IOT_SENSORDATA_NAMESPACE = "urn:xmpp:iot:data";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public abstract class IoTDataField implements NamedElement {
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
integer("int"),
|
||||||
|
bool("boolean"),
|
||||||
|
;
|
||||||
|
|
||||||
|
Type(String stringRepresentation) {
|
||||||
|
this.stringRepresentation = stringRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String stringRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Type type;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
protected IoTDataField(Type type, String name) {
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String getElementName() {
|
||||||
|
return type.stringRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.attribute("name", name).attribute("value", getValueString());
|
||||||
|
// TODO handle 'unit' attribute as special case if <numeric/> is implemented.
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String valueString;
|
||||||
|
|
||||||
|
public final String getValueString() {
|
||||||
|
if (valueString == null) {
|
||||||
|
valueString = getValueInternal();
|
||||||
|
}
|
||||||
|
return valueString;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getValueInternal();
|
||||||
|
|
||||||
|
public static class IntField extends IoTDataField {
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
public IntField(String name, int value) {
|
||||||
|
super(Type.integer, name);
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getValueInternal() {
|
||||||
|
return Integer.toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BooleanField extends IoTDataField {
|
||||||
|
|
||||||
|
private final boolean value;
|
||||||
|
|
||||||
|
public BooleanField(String name, boolean value) {
|
||||||
|
super(Type.bool, name);
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getValueInternal() {
|
||||||
|
return Boolean.toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
|
||||||
|
public class IoTDataReadOutAccepted extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "accepted";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_SENSORDATA_NAMESPACE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sequence number. According to XEP-0323 an xs:int.
|
||||||
|
*/
|
||||||
|
private final int seqNr;
|
||||||
|
|
||||||
|
private final boolean queued;
|
||||||
|
|
||||||
|
public IoTDataReadOutAccepted(int seqNr, boolean queued) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.seqNr = seqNr;
|
||||||
|
this.queued = queued;
|
||||||
|
setType(Type.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTDataReadOutAccepted(IoTDataRequest dataRequest) {
|
||||||
|
this(dataRequest.getSequenceNr(), false);
|
||||||
|
setStanzaId(dataRequest.getStanzaId());
|
||||||
|
setTo(dataRequest.getFrom());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.attribute("seqnr", seqNr);
|
||||||
|
xml.optBooleanAttribute("queued", queued);
|
||||||
|
xml.setEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
|
||||||
|
public class IoTDataRequest extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "req";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_SENSORDATA_NAMESPACE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sequence nummber. According to XEP-0323 an xs:int.
|
||||||
|
*/
|
||||||
|
private final int seqNr;
|
||||||
|
|
||||||
|
private final boolean momentary;
|
||||||
|
|
||||||
|
public IoTDataRequest(int seqNr, boolean momentary) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.seqNr = seqNr;
|
||||||
|
this.momentary = momentary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSequenceNr() {
|
||||||
|
return seqNr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.attribute("seqnr", seqNr);
|
||||||
|
xml.optBooleanAttribute("momentary", momentary);
|
||||||
|
xml.setEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMomentary() {
|
||||||
|
return momentary;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.element;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
|
||||||
|
public class IoTFieldsExtension implements ExtensionElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "fields";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_SENSORDATA_NAMESPACE;
|
||||||
|
|
||||||
|
private final int seqNr;
|
||||||
|
private final boolean done;
|
||||||
|
private final List<NodeElement> nodes;
|
||||||
|
|
||||||
|
public IoTFieldsExtension(int seqNr, boolean done, NodeElement node) {
|
||||||
|
this(seqNr, done, Collections.singletonList(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTFieldsExtension(int seqNr, boolean done, List<NodeElement> nodes) {
|
||||||
|
this.seqNr = seqNr;
|
||||||
|
this.done = done;
|
||||||
|
this.nodes = Collections.unmodifiableList(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSequenceNr() {
|
||||||
|
return seqNr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDone() {
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NodeElement> getNodes() {
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.attribute("seqnr", Integer.toString(seqNr));
|
||||||
|
xml.attribute("done", done);
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
xml.append(nodes);
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IoTFieldsExtension buildFor(int seqNr, boolean done, NodeInfo nodeInfo,
|
||||||
|
List<? extends IoTDataField> data) {
|
||||||
|
TimestampElement timestampElement = new TimestampElement(new Date(), data);
|
||||||
|
NodeElement nodeElement = new NodeElement(nodeInfo, timestampElement);
|
||||||
|
return new IoTFieldsExtension(seqNr, done, nodeElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IoTFieldsExtension from(Message message) {
|
||||||
|
return message.getExtension(ELEMENT, NAMESPACE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.element;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
|
||||||
|
public class NodeElement implements NamedElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "node";
|
||||||
|
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
private final List<TimestampElement> timestampElements;
|
||||||
|
|
||||||
|
public NodeElement(NodeInfo nodeInfo, TimestampElement timestampElement) {
|
||||||
|
this(nodeInfo, Collections.singletonList(timestampElement));
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeElement(NodeInfo nodeInfo, List<TimestampElement> timestampElements) {
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
this.timestampElements = Collections.unmodifiableList(timestampElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TimestampElement> getTimestampElements() {
|
||||||
|
return timestampElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
nodeInfo.appendTo(xml);
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
xml.append(timestampElements);
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.element;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class TimestampElement implements NamedElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "timestamp";
|
||||||
|
|
||||||
|
private final Date date;
|
||||||
|
private final List<? extends IoTDataField> fields;
|
||||||
|
|
||||||
|
public TimestampElement(Date date, List<? extends IoTDataField> fields) {
|
||||||
|
this.date = date;
|
||||||
|
this.fields = Collections.unmodifiableList(fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<? extends IoTDataField> getDataFields() {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.attribute("value", date);
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
xml.append(fields);
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.data.element;
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.filter;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.filter.FlexibleStanzaTypeFilter;
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTFieldsExtension;
|
||||||
|
|
||||||
|
public class IoTFieldsExtensionFilter extends FlexibleStanzaTypeFilter<Message> {
|
||||||
|
|
||||||
|
private final int seqNr;
|
||||||
|
private final boolean onlyDone;
|
||||||
|
|
||||||
|
public IoTFieldsExtensionFilter(int seqNr, boolean onlyDone) {
|
||||||
|
this.seqNr = seqNr;
|
||||||
|
this.onlyDone = onlyDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean acceptSpecific(Message message) {
|
||||||
|
IoTFieldsExtension iotFieldsExtension = IoTFieldsExtension.from(message);
|
||||||
|
if (iotFieldsExtension == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (iotFieldsExtension.getSequenceNr() != seqNr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (onlyDone && !iotFieldsExtension.isDone()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.data.filter;
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.data;
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTDataReadOutAccepted;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTDataReadOutAcceptedProvider extends IQProvider<IoTDataReadOutAccepted> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTDataReadOutAccepted parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
int seqNr = ParserUtils.getIntegerAttributeOrThrow(parser, "seqnr", "IoT data request <accepted/> without sequence number");
|
||||||
|
boolean queued = ParserUtils.getBooleanAttribute(parser, "queued", false);
|
||||||
|
return new IoTDataReadOutAccepted(seqNr, queued);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTDataRequest;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTDataRequestProvider extends IQProvider<IoTDataRequest> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTDataRequest parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
int seqNr = ParserUtils.getIntegerAttributeOrThrow(parser, "seqnr", "IoT data request without sequence number");
|
||||||
|
boolean momentary = ParserUtils.getBooleanAttribute(parser, "momentary", false);
|
||||||
|
return new IoTDataRequest(seqNr, momentary);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.data.provider;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTDataField;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.IoTFieldsExtension;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.NodeElement;
|
||||||
|
import org.jivesoftware.smackx.iot.data.element.TimestampElement;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.parser.NodeInfoParser;
|
||||||
|
import org.jxmpp.util.XmppDateTime;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
public class IoTFieldsExtensionProvider extends ExtensionElementProvider<IoTFieldsExtension> {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(IoTFieldsExtensionProvider.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTFieldsExtension parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
int seqNr = ParserUtils.getIntegerAttributeOrThrow(parser, "seqnr", "IoT data request <accepted/> without sequence number");
|
||||||
|
boolean done = ParserUtils.getBooleanAttribute(parser, "done", false);
|
||||||
|
List<NodeElement> nodes = new ArrayList<>();
|
||||||
|
outerloop: while (true) {
|
||||||
|
final int eventType = parser.next();
|
||||||
|
final String name = parser.getName();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
switch (name) {
|
||||||
|
case NodeElement.ELEMENT:
|
||||||
|
NodeElement node = parseNode(parser);
|
||||||
|
nodes.add(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new IoTFieldsExtension(seqNr, done, nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeElement parseNode(XmlPullParser parser) throws XmlPullParserException, IOException, ParseException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
final NodeInfo nodeInfo = NodeInfoParser.parse(parser);
|
||||||
|
List<TimestampElement> timestampElements = new ArrayList<>();
|
||||||
|
outerloop: while (true) {
|
||||||
|
final int eventType = parser.next();
|
||||||
|
final String name = parser.getName();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
switch (name){
|
||||||
|
case TimestampElement.ELEMENT:
|
||||||
|
TimestampElement timestampElement = parseTimestampElement(parser);
|
||||||
|
timestampElements.add(timestampElement);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new NodeElement(nodeInfo, timestampElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimestampElement parseTimestampElement(XmlPullParser parser) throws ParseException, XmlPullParserException, IOException {
|
||||||
|
final int initialDepth = parser.getDepth();
|
||||||
|
final String dateString = parser.getAttributeValue(null, "value");
|
||||||
|
final Date date = XmppDateTime.parseDate(dateString);
|
||||||
|
List<IoTDataField> fields = new ArrayList<>();
|
||||||
|
outerloop: while (true) {
|
||||||
|
final int eventType = parser.next();
|
||||||
|
final String name = parser.getName();
|
||||||
|
switch (eventType) {
|
||||||
|
case XmlPullParser.START_TAG:
|
||||||
|
IoTDataField field = null;
|
||||||
|
final String fieldName = parser.getAttributeValue(null, "name");
|
||||||
|
final String fieldValue = parser.getAttributeValue(null, "value");
|
||||||
|
switch (name) {
|
||||||
|
case "int": {
|
||||||
|
int value = Integer.parseInt(fieldValue);
|
||||||
|
field = new IoTDataField.IntField(fieldName, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "boolean": {
|
||||||
|
boolean value = Boolean.parseBoolean(fieldValue);
|
||||||
|
field = new IoTDataField.BooleanField(fieldName, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGGER.warning("IoT Data field type '" + name + "' not implement yet. Ignoring.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (field != null) {
|
||||||
|
fields.add(field);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlPullParser.END_TAG:
|
||||||
|
if (parser.getDepth() == initialDepth) {
|
||||||
|
break outerloop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new TimestampElement(date, fields);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.data.provider;
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
public abstract class AbstractThingStateChangeListener implements ThingStateChangeListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void owned(BareJid owner) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.iot.IoTException;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTClaimed;
|
||||||
|
|
||||||
|
public class IoTClaimedException extends IoTException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final IoTClaimed iotClaimed;
|
||||||
|
|
||||||
|
public IoTClaimedException(IoTClaimed iotClaimed) {
|
||||||
|
this.iotClaimed = iotClaimed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTClaimed getIoTClaimed() {
|
||||||
|
return iotClaimed;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,420 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPConnectionRegistry;
|
||||||
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
|
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
|
||||||
|
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.Thing;
|
||||||
|
import org.jivesoftware.smackx.iot.control.IoTControlManager;
|
||||||
|
import org.jivesoftware.smackx.iot.data.IoTDataManager;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.Constants;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTClaimed;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTDisown;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTDisowned;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTMine;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTRegister;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTRemove;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTRemoved;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTUnregister;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.Tag;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manager for XEP-0347: Internet of Things - Discovery. Used to register and discover things.
|
||||||
|
*
|
||||||
|
* @author Florian Schmaus {@literal <flo@geekplace.eu>}
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0347.html">XEP-0347: Internet of Things - Discovery</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class IoTDiscoveryManager extends Manager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(IoTDiscoveryManager.class.getName());
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, IoTDiscoveryManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
// Ensure a IoTProvisioningManager exists for every connection.
|
||||||
|
static {
|
||||||
|
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
|
public void connectionCreated(XMPPConnection connection) {
|
||||||
|
getInstanceFor(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the manger instance responsible for the given connection.
|
||||||
|
*
|
||||||
|
* @param connection the XMPP connection.
|
||||||
|
* @return a manager instance.
|
||||||
|
*/
|
||||||
|
public static synchronized IoTDiscoveryManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
IoTDiscoveryManager manager = INSTANCES.get(connection);
|
||||||
|
if (manager == null) {
|
||||||
|
manager = new IoTDiscoveryManager(connection);
|
||||||
|
INSTANCES.put(connection, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Jid preconfiguredRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of all registries we have interacted so far. {@link #isRegistry(BareJid)} uses this to
|
||||||
|
* determine if the jid is a registry. Note that we currently do not record which thing
|
||||||
|
* interacted with which registry. This allows any registry we have interacted so far with, to
|
||||||
|
* send registry control stanzas about any other thing, and we would process them.
|
||||||
|
*/
|
||||||
|
private final Set<Jid> usedRegistries = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal state of the things. Uses <code>null</code> for the single thing without node info attached.
|
||||||
|
*/
|
||||||
|
private final Map<NodeInfo, ThingState> things = new HashMap<>();
|
||||||
|
|
||||||
|
private IoTDiscoveryManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
|
||||||
|
connection.registerIQRequestHandler(
|
||||||
|
new AbstractIqRequestHandler(IoTClaimed.ELEMENT, IoTClaimed.NAMESPACE, IQ.Type.set, Mode.sync) {
|
||||||
|
@Override
|
||||||
|
public IQ handleIQRequest(IQ iqRequest) {
|
||||||
|
if (!isRegistry(iqRequest.getFrom())) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Received control stanza from non-registry entity: " + iqRequest);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoTClaimed iotClaimed = (IoTClaimed) iqRequest;
|
||||||
|
Jid owner = iotClaimed.getJid();
|
||||||
|
NodeInfo nodeInfo = iotClaimed.getNodeInfo();
|
||||||
|
// Update the state.
|
||||||
|
ThingState state = getStateFor(nodeInfo);
|
||||||
|
state.setOwner(owner.asBareJid());
|
||||||
|
LOGGER.info("Our thing got claimed by " + owner + ". " + iotClaimed);
|
||||||
|
|
||||||
|
IoTProvisioningManager iotProvisioningManager = IoTProvisioningManager.getInstanceFor(
|
||||||
|
connection());
|
||||||
|
try {
|
||||||
|
iotProvisioningManager.sendFriendshipRequest(owner.asBareJid());
|
||||||
|
}
|
||||||
|
catch (NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not friendship owner", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IQ.createResultIQ(iqRequest);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.registerIQRequestHandler(new AbstractIqRequestHandler(IoTDisowned.ELEMENT, IoTDisowned.NAMESPACE,
|
||||||
|
IQ.Type.set, Mode.sync) {
|
||||||
|
@Override
|
||||||
|
public IQ handleIQRequest(IQ iqRequest) {
|
||||||
|
if (!isRegistry(iqRequest.getFrom())) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Received control stanza from non-registry entity: " + iqRequest);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoTDisowned iotDisowned = (IoTDisowned) iqRequest;
|
||||||
|
Jid from = iqRequest.getFrom();
|
||||||
|
|
||||||
|
NodeInfo nodeInfo = iotDisowned.getNodeInfo();
|
||||||
|
ThingState state = getStateFor(nodeInfo);
|
||||||
|
if (!from.equals(state.getRegistry())) {
|
||||||
|
LOGGER.severe("Received <disowned/> for " + nodeInfo + " from " + from
|
||||||
|
+ " but this is not the registry " + state.getRegistry() + " of the thing.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.isOwned()) {
|
||||||
|
state.setUnowned();
|
||||||
|
} else {
|
||||||
|
LOGGER.fine("Received <disowned/> for " + nodeInfo + " but thing was not owned.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return IQ.createResultIQ(iqRequest);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// XEP-0347 § 3.9 (ex28-29): <removed/>
|
||||||
|
connection.registerIQRequestHandler(new AbstractIqRequestHandler(IoTRemoved.ELEMENT, IoTRemoved.NAMESPACE, IQ.Type.set, Mode.async) {
|
||||||
|
@Override
|
||||||
|
public IQ handleIQRequest(IQ iqRequest) {
|
||||||
|
if (!isRegistry(iqRequest.getFrom())) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Received control stanza from non-registry entity: " + iqRequest);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoTRemoved iotRemoved = (IoTRemoved) iqRequest;
|
||||||
|
|
||||||
|
ThingState state = getStateFor(iotRemoved.getNodeInfo());
|
||||||
|
state.setRemoved();
|
||||||
|
|
||||||
|
// Unfriend registry. "It does this, so the Thing can remove the friendship and stop any
|
||||||
|
// meta data updates to the Registry."
|
||||||
|
try {
|
||||||
|
IoTProvisioningManager.getInstanceFor(connection()).unfriend(iotRemoved.getFrom());
|
||||||
|
}
|
||||||
|
catch (NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Could not unfriend registry after <removed/>", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IQ.createResultIQ(iqRequest);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to find an XMPP IoT registry.
|
||||||
|
*
|
||||||
|
* @return the JID of a Thing Registry if one could be found.
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0347.html#findingregistry">XEP-0347 § 3.5 Finding Thing Registry</a>
|
||||||
|
*/
|
||||||
|
public Jid findRegistry()
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
if (preconfiguredRegistry != null) {
|
||||||
|
return preconfiguredRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
final XMPPConnection connection = connection();
|
||||||
|
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
|
List<DiscoverInfo> discoverInfos = sdm.findServicesDiscoverInfo(Constants.IOT_DISCOVERY_NAMESPACE, true, true);
|
||||||
|
if (!discoverInfos.isEmpty()) {
|
||||||
|
return discoverInfos.get(0).getFrom();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thing Registration - XEP-0347 § 3.6 - 3.8
|
||||||
|
|
||||||
|
public ThingState registerThing(Thing thing)
|
||||||
|
throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException, IoTClaimedException {
|
||||||
|
Jid registry = findRegistry();
|
||||||
|
return registerThing(registry, thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThingState registerThing(Jid registry, Thing thing)
|
||||||
|
throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException, IoTClaimedException {
|
||||||
|
final XMPPConnection connection = connection();
|
||||||
|
IoTRegister iotRegister = new IoTRegister(thing.getMetaTags(), thing.getNodeInfo(), thing.isSelfOwened());
|
||||||
|
iotRegister.setTo(registry);
|
||||||
|
IQ result = connection.createPacketCollectorAndSend(iotRegister).nextResultOrThrow();
|
||||||
|
if (result instanceof IoTClaimed) {
|
||||||
|
IoTClaimed iotClaimedResult = (IoTClaimed) result;
|
||||||
|
throw new IoTClaimedException(iotClaimedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThingState state = getStateFor(thing.getNodeInfo());
|
||||||
|
state.setRegistry(registry.asBareJid());
|
||||||
|
|
||||||
|
interactWithRegistry(registry);
|
||||||
|
|
||||||
|
IoTDataManager.getInstanceFor(connection).installThing(thing);
|
||||||
|
IoTControlManager.getInstanceFor(connection).installThing(thing);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thing Claiming - XEP-0347 § 3.9
|
||||||
|
|
||||||
|
public IoTClaimed claimThing(Collection<Tag> metaTags) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
return claimThing(metaTags, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTClaimed claimThing(Collection<Tag> metaTags, boolean publicThing) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
Jid registry = findRegistry();
|
||||||
|
return claimThing(registry, metaTags, publicThing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Claim a thing by providing a collection of meta tags. If the claim was successful, then a {@link IoTClaimed}
|
||||||
|
* instance will be returned, which contains the XMPP address of the thing. Use {@link IoTClaimed#getJid()} to
|
||||||
|
* retrieve this address.
|
||||||
|
*
|
||||||
|
* @param registry the registry use to claim the thing.
|
||||||
|
* @param metaTags a collection of meta tags used to identify the thing.
|
||||||
|
* @param publicThing if this is a public thing.
|
||||||
|
* @return a {@link IoTClaimed} if successful.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
public IoTClaimed claimThing(Jid registry, Collection<Tag> metaTags, boolean publicThing) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
interactWithRegistry(registry);
|
||||||
|
|
||||||
|
IoTMine iotMine = new IoTMine(metaTags, publicThing);
|
||||||
|
iotMine.setTo(registry);
|
||||||
|
IoTClaimed iotClaimed = connection().createPacketCollectorAndSend(iotMine).nextResultOrThrow();
|
||||||
|
|
||||||
|
// The 'jid' attribute of the <claimed/> response now represents the XMPP address of the thing we just successfully claimed.
|
||||||
|
Jid thing = iotClaimed.getJid();
|
||||||
|
|
||||||
|
IoTProvisioningManager.getInstanceFor(connection()).sendFriendshipRequest(thing.asBareJid());
|
||||||
|
|
||||||
|
return iotClaimed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thing Removal - XEP-0347 § 3.10
|
||||||
|
|
||||||
|
public void removeThing(BareJid thing)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
removeThing(thing, NodeInfo.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeThing(BareJid thing, NodeInfo nodeInfo)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
Jid registry = findRegistry();
|
||||||
|
removeThing(registry, thing, nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeThing(Jid registry, BareJid thing, NodeInfo nodeInfo)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
interactWithRegistry(registry);
|
||||||
|
|
||||||
|
IoTRemove iotRemove = new IoTRemove(thing, nodeInfo);
|
||||||
|
iotRemove.setTo(registry);
|
||||||
|
connection().createPacketCollectorAndSend(iotRemove).nextResultOrThrow();
|
||||||
|
|
||||||
|
// We no not update the ThingState here, as this is done in the <removed/> IQ handler above.;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thing Unregistering - XEP-0347 § 3.16
|
||||||
|
|
||||||
|
public void unregister()
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
unregister(NodeInfo.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregister(NodeInfo nodeInfo)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
Jid registry = findRegistry();
|
||||||
|
unregister(registry, nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregister(Jid registry, NodeInfo nodeInfo)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
interactWithRegistry(registry);
|
||||||
|
|
||||||
|
IoTUnregister iotUnregister = new IoTUnregister(nodeInfo);
|
||||||
|
iotUnregister.setTo(registry);
|
||||||
|
connection().createPacketCollectorAndSend(iotUnregister).nextResultOrThrow();
|
||||||
|
|
||||||
|
ThingState state = getStateFor(nodeInfo);
|
||||||
|
state.setUnregistered();
|
||||||
|
|
||||||
|
final XMPPConnection connection = connection();
|
||||||
|
IoTDataManager.getInstanceFor(connection).uninstallThing(nodeInfo);
|
||||||
|
IoTControlManager.getInstanceFor(connection).uninstallThing(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thing Disowning - XEP-0347 § 3.17
|
||||||
|
|
||||||
|
public void disownThing(Jid thing)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
disownThing(thing, NodeInfo.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disownThing(Jid thing, NodeInfo nodeInfo)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
Jid registry = findRegistry();
|
||||||
|
disownThing(registry, thing, nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disownThing(Jid registry, Jid thing, NodeInfo nodeInfo)
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
interactWithRegistry(registry);
|
||||||
|
|
||||||
|
IoTDisown iotDisown = new IoTDisown(thing, nodeInfo);
|
||||||
|
iotDisown.setTo(registry);
|
||||||
|
connection().createPacketCollectorAndSend(iotDisown).nextResultOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registry utility methods
|
||||||
|
|
||||||
|
public boolean isRegistry(BareJid jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
// At some point 'usedRegistries' will also contain the registry returned by findRegistry(), but since this is
|
||||||
|
// not the case from the beginning, we perform findRegistry().equals(jid) too.
|
||||||
|
if (findRegistry().equals(jid)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (usedRegistries.contains(jid)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRegistry(Jid jid) {
|
||||||
|
try {
|
||||||
|
return isRegistry(jid.asBareJid());
|
||||||
|
}
|
||||||
|
catch (NoResponseException | XMPPErrorException | NotConnectedException
|
||||||
|
| InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not determine if " + jid + " is a registry", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void interactWithRegistry(Jid registry) throws NotConnectedException, InterruptedException {
|
||||||
|
boolean isNew = usedRegistries.add(registry);
|
||||||
|
if (!isNew) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IoTProvisioningManager iotProvisioningManager = IoTProvisioningManager.getInstanceFor(connection());
|
||||||
|
iotProvisioningManager.sendFriendshipRequestIfRequired(registry.asBareJid());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThingState getStateFor(Thing thing) {
|
||||||
|
return things.get(thing.getNodeInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThingState getStateFor(NodeInfo nodeInfo) {
|
||||||
|
ThingState state = things.get(nodeInfo);
|
||||||
|
if (state == null) {
|
||||||
|
state = new ThingState(nodeInfo);
|
||||||
|
things.put(nodeInfo, state);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.Async;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
public class ThingState {
|
||||||
|
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
|
||||||
|
private BareJid registry;
|
||||||
|
private BareJid owner;
|
||||||
|
private boolean removed;
|
||||||
|
|
||||||
|
private final List<ThingStateChangeListener> listeners = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
ThingState(NodeInfo nodeInfo) {
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRegistry(BareJid registry) {
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUnregistered() {
|
||||||
|
this.registry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOwner(final BareJid owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
Async.go(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (ThingStateChangeListener thingStateChangeListener : listeners) {
|
||||||
|
thingStateChangeListener.owned(owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUnowned() {
|
||||||
|
this.owner = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRemoved() {
|
||||||
|
removed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo getNodeInfo() {
|
||||||
|
return nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BareJid getRegistry() {
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BareJid getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOwned() {
|
||||||
|
return owner != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRemoved() {
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setThingStateChangeListener(ThingStateChangeListener thingStateChangeListener) {
|
||||||
|
return listeners.add(thingStateChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeThingStateChangeListener(ThingStateChangeListener thingStateChangeListener) {
|
||||||
|
return listeners.remove(thingStateChangeListener);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
public interface ThingStateChangeListener {
|
||||||
|
|
||||||
|
public void owned(BareJid owner);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
public static final String IOT_DISCOVERY_NAMESPACE = "urn:xmpp:iot:discovery";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
public class IoTClaimed extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "claimed";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_DISCOVERY_NAMESPACE;
|
||||||
|
|
||||||
|
private final Jid jid;
|
||||||
|
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
|
||||||
|
public IoTClaimed(Jid jid) {
|
||||||
|
this(jid, NodeInfo.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTClaimed(Jid jid, NodeInfo nodeInfo) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.jid = jid;
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jid getJid() {
|
||||||
|
return jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeInfo.getNodeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceId() {
|
||||||
|
return nodeInfo.getSourceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo getNodeInfo() {
|
||||||
|
return nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.attribute("jid", jid);
|
||||||
|
nodeInfo.appendTo(xml);
|
||||||
|
xml.setEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
public class IoTDisown extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "disown";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_DISCOVERY_NAMESPACE;
|
||||||
|
|
||||||
|
private final Jid jid;
|
||||||
|
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
|
||||||
|
public IoTDisown(Jid jid) {
|
||||||
|
this(jid, NodeInfo.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTDisown(Jid jid, NodeInfo nodeInfo) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.jid = jid;
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jid getJid() {
|
||||||
|
return jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeInfo != null ? nodeInfo.getNodeId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceId() {
|
||||||
|
return nodeInfo != null ? nodeInfo.getSourceId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.attribute("jid", jid);
|
||||||
|
nodeInfo.appendTo(xml);
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
|
||||||
|
public class IoTDisowned extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "disown";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_DISCOVERY_NAMESPACE;
|
||||||
|
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
|
||||||
|
public IoTDisowned(NodeInfo nodeInfo) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeInfo.getNodeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceId() {
|
||||||
|
return nodeInfo.getSourceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo getNodeInfo() {
|
||||||
|
return nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
nodeInfo.appendTo(xml);
|
||||||
|
xml.setEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
|
||||||
|
public class IoTMine extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "mine";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_DISCOVERY_NAMESPACE;
|
||||||
|
|
||||||
|
private final List<Tag> metaTags;
|
||||||
|
private final boolean publicThing;
|
||||||
|
|
||||||
|
public IoTMine(Collection<Tag> metaTags, boolean publicThing) {
|
||||||
|
this(new ArrayList<>(metaTags), publicThing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTMine(List<Tag> metaTags, boolean publicThing) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.metaTags = metaTags;
|
||||||
|
this.publicThing = publicThing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.optBooleanAttributeDefaultTrue("public", publicThing);
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
xml.append(metaTags);
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
|
||||||
|
public class IoTRegister extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "register";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_DISCOVERY_NAMESPACE;
|
||||||
|
|
||||||
|
private final Collection<Tag> tags;
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
private final boolean selfOwned;
|
||||||
|
|
||||||
|
public IoTRegister(Collection<Tag> tags, NodeInfo nodeInfo, boolean selfOwned) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
if (tags.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
this.tags = tags;
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
this.selfOwned = selfOwned;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
nodeInfo.appendTo(xml);
|
||||||
|
xml.optBooleanAttribute("selfOwned", selfOwned);
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
xml.append(tags);
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
public class IoTRemove extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "remove";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_DISCOVERY_NAMESPACE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The XMPP address of the Thing to be removed from the registry. According to XEP-0347 § 3.10 the
|
||||||
|
* "resource-less JID of the Thing" has to be used, therefore we use {@link BareJid} here.
|
||||||
|
*/
|
||||||
|
private final BareJid jid;
|
||||||
|
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
|
||||||
|
public IoTRemove(BareJid jid) {
|
||||||
|
this(jid, NodeInfo.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTRemove(BareJid jid, NodeInfo nodeInfo) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.jid = jid;
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jid getJid() {
|
||||||
|
return jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeInfo != null ? nodeInfo.getNodeId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceId() {
|
||||||
|
return nodeInfo != null ? nodeInfo.getSourceId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.attribute("jid", jid);
|
||||||
|
nodeInfo.appendTo(xml);
|
||||||
|
xml.setEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
|
||||||
|
public class IoTRemoved extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "removed";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_DISCOVERY_NAMESPACE;
|
||||||
|
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
|
||||||
|
public IoTRemoved() {
|
||||||
|
this(NodeInfo.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoTRemoved(NodeInfo nodeInfo) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeInfo.getNodeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceId() {
|
||||||
|
return nodeInfo.getSourceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo getNodeInfo() {
|
||||||
|
return nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
nodeInfo.appendTo(xml);
|
||||||
|
xml.setEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
|
||||||
|
public class IoTUnregister extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "unregister";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_DISCOVERY_NAMESPACE;
|
||||||
|
|
||||||
|
private final NodeInfo nodeInfo;
|
||||||
|
|
||||||
|
public IoTUnregister(NodeInfo nodeInfo) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.nodeInfo = nodeInfo;
|
||||||
|
setType(Type.set);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
nodeInfo.appendTo(xml);
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.Objects;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class Tag implements NamedElement {
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
str,
|
||||||
|
num;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final Type type;
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
public Tag(String name, Type type, String value) {
|
||||||
|
// TODO According to XEP-0347 § 5.2 names are case insensitive. Uppercase them all?
|
||||||
|
this.name = StringUtils.requireNotNullOrEmpty(name, "name must not be null or empty");
|
||||||
|
this.type = Objects.requireNonNull(type);
|
||||||
|
this.value = StringUtils.requireNotNullOrEmpty(value, "value must not be null or empty");
|
||||||
|
if (this.name.length() > 32) {
|
||||||
|
throw new IllegalArgumentException("Meta Tag names must not be longer then 32 characters (XEP-0347 § 5.2");
|
||||||
|
}
|
||||||
|
if (this.type == Type.str && this.value.length() > 128) {
|
||||||
|
throw new IllegalArgumentException("Meta Tag string values must not be longer then 128 characters (XEP-0347 § 5.2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.attribute("name", name);
|
||||||
|
xml.attribute("value", value);
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return getType().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name + '(' + type + "):" + value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.discovery.element;
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT XEP-0347 Discovery. See {@link org.jivesoftware.smackx.iot.discovery.IoTDiscoveryManager}.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.discovery;
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTClaimed;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.parser.NodeInfoParser;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTClaimedProvider extends IQProvider<IoTClaimed> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTClaimed parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
Jid jid = ParserUtils.getJidAttribute(parser);
|
||||||
|
NodeInfo nodeInfo = NodeInfoParser.parse(parser);
|
||||||
|
return new IoTClaimed(jid, nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTDisown;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.parser.NodeInfoParser;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTDisownProvider extends IQProvider<IoTDisown> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTDisown parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
Jid jid = ParserUtils.getJidAttribute(parser);
|
||||||
|
NodeInfo nodeInfo = NodeInfoParser.parse(parser);
|
||||||
|
return new IoTDisown(jid, nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTDisowned;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.parser.NodeInfoParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTDisownedProvider extends IQProvider<IoTDisowned> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTDisowned parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
NodeInfo nodeInfo = NodeInfoParser.parse(parser);
|
||||||
|
return new IoTDisowned(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.provider;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTRegister;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.Tag;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.parser.NodeInfoParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTRegisterProvider extends IQProvider<IoTRegister> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTRegister parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
boolean selfOwned = ParserUtils.getBooleanAttribute(parser, "selfOwned", false);
|
||||||
|
NodeInfo nodeInfo = NodeInfoParser.parse(parser);
|
||||||
|
List<Tag> tags = new ArrayList<>();
|
||||||
|
while (parser.getDepth() != initialDepth) {
|
||||||
|
int event = parser.next();
|
||||||
|
if (event != XmlPullParser.START_TAG) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final String element = parser.getName();
|
||||||
|
Tag.Type type = null;
|
||||||
|
switch (element) {
|
||||||
|
case "str":
|
||||||
|
type = Tag.Type.str;
|
||||||
|
break;
|
||||||
|
case "num":
|
||||||
|
type = Tag.Type.num;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (type == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = parser.getAttributeValue(null, "name");
|
||||||
|
String value = parser.getAttributeValue(null, "value");
|
||||||
|
tags.add(new Tag(name, type, value));
|
||||||
|
}
|
||||||
|
return new IoTRegister(tags, nodeInfo, selfOwned);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTRemove;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.parser.NodeInfoParser;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTRemoveProvider extends IQProvider<IoTRemove> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTRemove parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
Jid jid = ParserUtils.getJidAttribute(parser);
|
||||||
|
if (jid.hasResource()) {
|
||||||
|
throw new SmackException("JID must be without resourcepart");
|
||||||
|
}
|
||||||
|
BareJid bareJid = jid.asBareJid();
|
||||||
|
NodeInfo nodeInfo = NodeInfoParser.parse(parser);
|
||||||
|
return new IoTRemove(bareJid, nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTRemoved;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.parser.NodeInfoParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTRemovedProvider extends IQProvider<IoTRemoved> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTRemoved parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
NodeInfo nodeInfo = NodeInfoParser.parse(parser);
|
||||||
|
return new IoTRemoved(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.discovery.provider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.provider.IQProvider;
|
||||||
|
import org.jivesoftware.smackx.iot.discovery.element.IoTUnregister;
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.jivesoftware.smackx.iot.parser.NodeInfoParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTUnregisterProvider extends IQProvider<IoTUnregister> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTUnregister parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
NodeInfo nodeInfo = NodeInfoParser.parse(parser);
|
||||||
|
return new IoTUnregister(nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.discovery.provider;
|
|
@ -0,0 +1,105 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public final class NodeInfo {
|
||||||
|
|
||||||
|
public static final NodeInfo EMPTY = new NodeInfo();
|
||||||
|
|
||||||
|
private final String nodeId;
|
||||||
|
private final String sourceId;
|
||||||
|
private final String cacheType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal constructor for the {@link EMPTY} node info marker class.
|
||||||
|
*/
|
||||||
|
private NodeInfo() {
|
||||||
|
this.nodeId = null;
|
||||||
|
this.sourceId = null;
|
||||||
|
this.cacheType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo(String nodeId, String sourceId, String cacheType) {
|
||||||
|
this.nodeId = StringUtils.requireNotNullOrEmpty(nodeId, "Node ID must not be null or empty");
|
||||||
|
this.sourceId = sourceId;
|
||||||
|
this.cacheType = cacheType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeId() {
|
||||||
|
return nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceId() {
|
||||||
|
return sourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCacheType() {
|
||||||
|
return cacheType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendTo(XmlStringBuilder xml) {
|
||||||
|
if (nodeId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xml.attribute("nodeId", nodeId).optAttribute("sourceId", sourceId).optAttribute("cacheType", cacheType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
if (this == EMPTY) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + nodeId.hashCode();
|
||||||
|
result = prime * result + ((sourceId == null) ? 0 : sourceId.hashCode());
|
||||||
|
result = prime * result + ((cacheType == null) ? 0 : cacheType.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (this == other) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(other instanceof NodeInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NodeInfo otherNodeInfo = (NodeInfo) other;
|
||||||
|
if (!nodeId.equals(otherNodeInfo.nodeId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (StringUtils.nullSafeCharSequenceEquals(sourceId, otherNodeInfo.sourceId)
|
||||||
|
&& StringUtils.nullSafeCharSequenceEquals(cacheType, otherNodeInfo.cacheType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static void eventuallyAppend(NodeInfo nodeInfo, XmlStringBuilder xml) {
|
||||||
|
// if (nodeInfo == null)
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
// nodeInfo.appendTo(xml);
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.element;
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot;
|
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.parser;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.iot.element.NodeInfo;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
import static org.jivesoftware.smack.util.StringUtils.isNullOrEmpty;
|
||||||
|
|
||||||
|
public class NodeInfoParser {
|
||||||
|
|
||||||
|
public static NodeInfo parse(XmlPullParser parser) {
|
||||||
|
String nodeId = parser.getAttributeValue(null, "nodeId");
|
||||||
|
String sourceId = parser.getAttributeValue(null, "sourceId");
|
||||||
|
String cacheType = parser.getAttributeValue(null, "cacheType");
|
||||||
|
if (isNullOrEmpty(nodeId) && isNullOrEmpty(sourceId) && isNullOrEmpty(cacheType)) {
|
||||||
|
return NodeInfo.EMPTY;
|
||||||
|
}
|
||||||
|
return new NodeInfo(nodeId, sourceId, cacheType);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.parser;
|
|
@ -0,0 +1,319 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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 java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
|
import org.jivesoftware.smack.Manager;
|
||||||
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
|
import org.jivesoftware.smack.StanzaListener;
|
||||||
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
|
import org.jivesoftware.smack.XMPPConnectionRegistry;
|
||||||
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
|
import org.jivesoftware.smack.filter.AndFilter;
|
||||||
|
import org.jivesoftware.smack.filter.StanzaExtensionFilter;
|
||||||
|
import org.jivesoftware.smack.filter.StanzaFilter;
|
||||||
|
import org.jivesoftware.smack.filter.StanzaTypeFilter;
|
||||||
|
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
|
||||||
|
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
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.Roster;
|
||||||
|
import org.jivesoftware.smack.roster.RosterEntry;
|
||||||
|
import org.jivesoftware.smack.roster.SubscribeListener;
|
||||||
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||||
|
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.IoTIsFriend;
|
||||||
|
import org.jivesoftware.smackx.iot.provisioning.element.IoTIsFriendResponse;
|
||||||
|
import org.jivesoftware.smackx.iot.provisioning.element.Unfriend;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.jxmpp.util.cache.LruCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manager for XEP-0324: Internet of Things - Provisioning.
|
||||||
|
*
|
||||||
|
* @author Florian Schmaus {@literal <flo@geekplace.eu>}
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0324.html">XEP-0324: Internet of Things - Provisioning</a>
|
||||||
|
*/
|
||||||
|
public final class IoTProvisioningManager extends Manager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(IoTProvisioningManager.class.getName());
|
||||||
|
|
||||||
|
private static final StanzaFilter UNFRIEND_MESSAGE = new AndFilter(StanzaTypeFilter.MESSAGE,
|
||||||
|
new StanzaExtensionFilter(Unfriend.ELEMENT, Unfriend.NAMESPACE));
|
||||||
|
|
||||||
|
private static final Map<XMPPConnection, IoTProvisioningManager> INSTANCES = new WeakHashMap<>();
|
||||||
|
|
||||||
|
// Ensure a IoTProvisioningManager exists for every connection.
|
||||||
|
static {
|
||||||
|
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||||
|
public void connectionCreated(XMPPConnection connection) {
|
||||||
|
getInstanceFor(connection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the manger instance responsible for the given connection.
|
||||||
|
*
|
||||||
|
* @param connection the XMPP connection.
|
||||||
|
* @return a manager instance.
|
||||||
|
*/
|
||||||
|
public static synchronized IoTProvisioningManager getInstanceFor(XMPPConnection connection) {
|
||||||
|
IoTProvisioningManager manager = INSTANCES.get(connection);
|
||||||
|
if (manager == null) {
|
||||||
|
manager = new IoTProvisioningManager(connection);
|
||||||
|
INSTANCES.put(connection, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Roster roster;
|
||||||
|
private final LruCache<Jid, LruCache<BareJid, Void>> negativeFriendshipRequestCache = new LruCache<>(8);
|
||||||
|
|
||||||
|
private Jid configuredProvisioningServer;
|
||||||
|
|
||||||
|
private IoTProvisioningManager(XMPPConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
|
||||||
|
// Stanza listener for XEP-0324 § 3.2.3.
|
||||||
|
connection.addAsyncStanzaListener(new StanzaListener() {
|
||||||
|
@Override
|
||||||
|
public void processPacket(Stanza stanza) throws NotConnectedException, InterruptedException {
|
||||||
|
if (!isFromProvisioningService(stanza)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Message message = (Message) stanza;
|
||||||
|
Unfriend unfriend = Unfriend.from(message);
|
||||||
|
BareJid unfriendJid = unfriend.getJid();
|
||||||
|
final XMPPConnection connection = connection();
|
||||||
|
Roster roster = Roster.getInstanceFor(connection);
|
||||||
|
if (!roster.isSubscribedToMyPresence(unfriendJid)) {
|
||||||
|
LOGGER.warning("Ignoring <unfriend/> request '" + stanza + "' because " + unfriendJid
|
||||||
|
+ " is already not subscribed to our presence.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Presence unsubscribed = new Presence(Presence.Type.unsubscribed);
|
||||||
|
unsubscribed.setTo(unfriendJid);
|
||||||
|
connection.sendStanza(unsubscribed);
|
||||||
|
}
|
||||||
|
}, UNFRIEND_MESSAGE);
|
||||||
|
|
||||||
|
connection.registerIQRequestHandler(
|
||||||
|
new AbstractIqRequestHandler(ClearCache.ELEMENT, ClearCache.NAMESPACE, Type.set, Mode.async) {
|
||||||
|
@Override
|
||||||
|
public IQ handleIQRequest(IQ iqRequest) {
|
||||||
|
if (!isFromProvisioningService(iqRequest)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearCache clearCache = (ClearCache) iqRequest;
|
||||||
|
|
||||||
|
// Handle <clearCache/> request.
|
||||||
|
Jid from = iqRequest.getFrom();
|
||||||
|
LruCache<BareJid, Void> cache = negativeFriendshipRequestCache.get(from);
|
||||||
|
if (cache != null) {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ClearCacheResponse(clearCache);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
roster = Roster.getInstanceFor(connection);
|
||||||
|
roster.setSubscribeListener(new SubscribeListener() {
|
||||||
|
@Override
|
||||||
|
public SubscribeAnswer processSubscribe(Jid from, Presence subscribeRequest) {
|
||||||
|
// First check if the subscription request comes from a known registry and accept the request if so.
|
||||||
|
try {
|
||||||
|
if (IoTDiscoveryManager.getInstanceFor(connection()).isRegistry(from.asBareJid())) {
|
||||||
|
return SubscribeAnswer.Approve;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NoResponseException | XMPPErrorException | NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not determine if " + from + " is a registry", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Jid provisioningServer = null;
|
||||||
|
try {
|
||||||
|
provisioningServer = getConfiguredProvisioningServer();
|
||||||
|
}
|
||||||
|
catch (NoResponseException | XMPPErrorException | NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING,
|
||||||
|
"Could not determine privisioning server. Ignoring friend request from " + from, e);
|
||||||
|
}
|
||||||
|
if (provisioningServer == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isFriend;
|
||||||
|
try {
|
||||||
|
isFriend = isFriend(provisioningServer, from.asBareJid());
|
||||||
|
}
|
||||||
|
catch (NoResponseException | XMPPErrorException | NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not determine if " + from + " is a friend.", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFriend) {
|
||||||
|
return SubscribeAnswer.Approve;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return SubscribeAnswer.Deny;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the configured provisioning server. Use <code>null</code> as provisioningServer to use
|
||||||
|
* automatic discovery of the provisioning server (the default behavior).
|
||||||
|
*
|
||||||
|
* @param provisioningServer
|
||||||
|
*/
|
||||||
|
public void setConfiguredProvisioningServer(Jid provisioningServer) {
|
||||||
|
this.configuredProvisioningServer = provisioningServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jid getConfiguredProvisioningServer()
|
||||||
|
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
if (configuredProvisioningServer == null) {
|
||||||
|
configuredProvisioningServer = findProvisioningServerComponent();
|
||||||
|
}
|
||||||
|
return configuredProvisioningServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to find a provisioning server component.
|
||||||
|
*
|
||||||
|
* @return the XMPP address of the provisioning server component if one was found.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0324.html#servercomponent">XEP-0324 § 3.1.2 Provisioning Server as a server component</a>
|
||||||
|
*/
|
||||||
|
public DomainBareJid findProvisioningServerComponent() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
final XMPPConnection connection = connection();
|
||||||
|
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
|
List<DiscoverInfo> discoverInfos = sdm.findServicesDiscoverInfo(Constants.IOT_PROVISIONING_NAMESPACE, true, true);
|
||||||
|
if (discoverInfos.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Jid jid = discoverInfos.get(0).getFrom();
|
||||||
|
assert (jid.isDomainBareJid());
|
||||||
|
return jid.asDomainBareJid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As the given provisioning server is the given JID is a friend.
|
||||||
|
*
|
||||||
|
* @param provisioningServer the provisioning server to ask.
|
||||||
|
* @param friendInQuestion the JID to ask about.
|
||||||
|
* @return <code>true</code> if the JID is a friend, <code>false</code> otherwise.
|
||||||
|
* @throws NoResponseException
|
||||||
|
* @throws XMPPErrorException
|
||||||
|
* @throws NotConnectedException
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
public boolean isFriend(Jid provisioningServer, BareJid friendInQuestion) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
|
||||||
|
LruCache<BareJid, Void> cache = negativeFriendshipRequestCache.get(provisioningServer);
|
||||||
|
if (cache != null && cache.containsKey(friendInQuestion)) {
|
||||||
|
// We hit a cached negative isFriend response for this provisioning server.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoTIsFriend iotIsFriend = new IoTIsFriend(friendInQuestion);
|
||||||
|
iotIsFriend.setTo(provisioningServer);
|
||||||
|
IoTIsFriendResponse response = connection().createPacketCollectorAndSend(iotIsFriend).nextResultOrThrow();
|
||||||
|
assert (response.getJid().equals(friendInQuestion));
|
||||||
|
boolean isFriend = response.getIsFriendResult();
|
||||||
|
if (!isFriend) {
|
||||||
|
// Cache the negative is friend response.
|
||||||
|
if (cache == null) {
|
||||||
|
cache = new LruCache<>(1024);
|
||||||
|
negativeFriendshipRequestCache.put(provisioningServer, cache);
|
||||||
|
}
|
||||||
|
cache.put(friendInQuestion, null);
|
||||||
|
}
|
||||||
|
return isFriend;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendFriendshipRequest(BareJid bareJid) throws NotConnectedException, InterruptedException {
|
||||||
|
Presence presence = new Presence(Presence.Type.subscribe);
|
||||||
|
presence.setTo(bareJid);
|
||||||
|
connection().sendStanza(presence);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendFriendshipRequestIfRequired(BareJid jid) throws NotConnectedException, InterruptedException {
|
||||||
|
RosterEntry entry = roster.getEntry(jid);
|
||||||
|
if (entry != null && entry.canSeeHisPresence()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendFriendshipRequest(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBefriended(Jid friendInQuestion) {
|
||||||
|
return roster.isSubscribedToMyPresence(friendInQuestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unfriend(Jid friend) throws NotConnectedException, InterruptedException {
|
||||||
|
if (isBefriended(friend)) {
|
||||||
|
Presence presence = new Presence(Presence.Type.unsubscribed);
|
||||||
|
presence.setTo(friend);
|
||||||
|
connection().sendStanza(presence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isFromProvisioningService(Stanza stanza) {
|
||||||
|
Jid provisioningServer;
|
||||||
|
try {
|
||||||
|
provisioningServer = getConfiguredProvisioningServer();
|
||||||
|
}
|
||||||
|
catch (NotConnectedException | InterruptedException | NoResponseException | XMPPErrorException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could determine provisioning server", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (provisioningServer == null) {
|
||||||
|
LOGGER.warning("Ignoring request '" + stanza
|
||||||
|
+ "' because no provisioning server configured.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!provisioningServer.equals(stanza.getFrom())) {
|
||||||
|
LOGGER.warning("Ignoring request '" + stanza + "' because not from provising server '"
|
||||||
|
+ provisioningServer + "'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.SimpleIQ;
|
||||||
|
|
||||||
|
public class ClearCache extends SimpleIQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "clearCache";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_PROVISIONING_NAMESPACE;
|
||||||
|
|
||||||
|
public ClearCache() {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
// <clearCache/> IQs are always of type 'get' (XEP-0324 § 3.5.1, see also the XEPs history remarks)
|
||||||
|
setType(Type.get);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.SimpleIQ;
|
||||||
|
|
||||||
|
public class ClearCacheResponse extends SimpleIQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "clearCacheResponse";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_PROVISIONING_NAMESPACE;
|
||||||
|
|
||||||
|
public ClearCacheResponse() {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
// <clearCacheResponse/> IQs are always of type 'result' (XEP-0324 § 3.5.1, see also the XEPs history remarks)
|
||||||
|
setType(Type.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClearCacheResponse(ClearCache clearCacheRequest) {
|
||||||
|
this();
|
||||||
|
setStanzaId(clearCacheRequest.getStanzaId());
|
||||||
|
setTo(clearCacheRequest.getFrom());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
public static final String IOT_PROVISIONING_NAMESPACE = "urn:xmpp:iot:provisioning";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.IQ;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
public class IoTIsFriend extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "isFriend";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_PROVISIONING_NAMESPACE;
|
||||||
|
|
||||||
|
private final Jid jid;
|
||||||
|
|
||||||
|
public IoTIsFriend(Jid jid) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.jid = jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.attribute("jid", jid);
|
||||||
|
xml.setEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.IQ;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
public class IoTIsFriendResponse extends IQ {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "isFriend";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_PROVISIONING_NAMESPACE;
|
||||||
|
|
||||||
|
private final BareJid jid;
|
||||||
|
|
||||||
|
private final boolean result;
|
||||||
|
|
||||||
|
public IoTIsFriendResponse(BareJid jid, boolean result) {
|
||||||
|
super(ELEMENT, NAMESPACE);
|
||||||
|
this.jid = jid;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BareJid getJid() {
|
||||||
|
return jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getIsFriendResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
|
||||||
|
xml.attribute("jid", jid);
|
||||||
|
xml.attribute("result", result);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.XmlStringBuilder;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
|
||||||
|
public class Unfriend implements ExtensionElement {
|
||||||
|
public static final String ELEMENT = "UNFRIEND";
|
||||||
|
public static final String NAMESPACE = Constants.IOT_PROVISIONING_NAMESPACE;
|
||||||
|
|
||||||
|
private final BareJid jid;
|
||||||
|
|
||||||
|
public Unfriend(BareJid jid) {
|
||||||
|
this.jid = jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BareJid getJid() {
|
||||||
|
return jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.attribute("jid", jid);
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Unfriend from(Message message) {
|
||||||
|
return message.getExtension(ELEMENT, NAMESPACE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.provisioning.element;
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.provisioning;
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.IQProvider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.iot.provisioning.element.ClearCache;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class ClearCacheProvider extends IQProvider<ClearCache> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClearCache parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
return new ClearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.IQProvider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smackx.iot.provisioning.element.ClearCacheResponse;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class ClearCacheResponseProvider extends IQProvider<ClearCacheResponse> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClearCacheResponse parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
return new ClearCacheResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.IQProvider;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.provisioning.element.IoTIsFriend;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTIsFriendProvider extends IQProvider<IoTIsFriend> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTIsFriend parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
Jid jid = ParserUtils.getJidAttribute(parser);
|
||||||
|
return new IoTIsFriend(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.IQProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.iot.provisioning.element.IoTIsFriendResponse;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class IoTIsFriendResponseProvider extends IQProvider<IoTIsFriendResponse> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoTIsFriendResponse parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
Jid jid = ParserUtils.getJidAttribute(parser);
|
||||||
|
BareJid bareJid = jid.asBareJid();
|
||||||
|
boolean result = ParserUtils.getBooleanAttribute(parser, "result");
|
||||||
|
|
||||||
|
return new IoTIsFriendResponse(bareJid, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.Unfriend;
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class UnfriendProvider extends ExtensionElementProvider<Unfriend> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Unfriend parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
BareJid jid = ParserUtils.getBareJidAttribute(parser);
|
||||||
|
return new Unfriend(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smack's API for XMPP IoT.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.iot.provisioning.provider;
|
|
@ -52,4 +52,97 @@
|
||||||
<className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
|
<className>org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0347: Internet of Things - Discovery -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>register</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRegisterProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>claimed</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTClaimedProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>disown</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTDisownProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>disowned</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTDisownedProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>remove</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRemoveProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>disown</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTRemovedProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>unregister</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:discovery</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.discovery.provider.IoTUnregisterProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0324: Internet of Things - Provisioning -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>isFriend</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:provisioning</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.provisioning.provider.IoTIsFriendProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>isFriendResponse</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:provisioning</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.provisioning.provider.IoTIsFriendResponseProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>clearCache</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:provisioning</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.provisioning.provider.ClearCacheProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>clearCacheResponse</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:provisioning</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.provisioning.provider.ClearCacheResponseProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>unfriend</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:provisioning</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.provisioning.provider.UnfriendProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0323: Internet of Things - Data -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>req</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:data</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.data.provider.IoTDataRequestProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>accepted</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:data</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.data.provider.IoTDataReadOutAcceptedProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>fields</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:data</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.data.provider.IoTFieldsExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0325: Internet of Things - Control -->
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>set</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:control</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.control.provider.IoTSetRequestProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
<iqProvider>
|
||||||
|
<elementName>setResponse</elementName>
|
||||||
|
<namespace>urn:xmpp:iot:control</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.iot.control.provider.IoTSetResponseProvider</className>
|
||||||
|
</iqProvider>
|
||||||
|
|
||||||
</smackProviders>
|
</smackProviders>
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<smack>
|
<smack>
|
||||||
<startupClasses>
|
<startupClasses>
|
||||||
<className>org.jivesoftware.smackx.hoxt.HOXTManager</className>
|
<className>org.jivesoftware.smackx.hoxt.HOXTManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.iot.data.IoTDataManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.iot.discovery.IoTDiscoveryManager</className>
|
||||||
|
<className>org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager</className>
|
||||||
</startupClasses>
|
</startupClasses>
|
||||||
</smack>
|
</smack>
|
|
@ -1074,13 +1074,7 @@ public final class Roster extends Manager {
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (entry.getType()) {
|
return entry.canSeeMyPresence();
|
||||||
case from:
|
|
||||||
case both:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -176,6 +176,39 @@ public final class RosterEntry extends Manager {
|
||||||
return item.isSubscriptionPending();
|
return item.isSubscriptionPending();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the contact is subscribed to "my" presence. This allows the contact to see the presence information.
|
||||||
|
*
|
||||||
|
* @return true if the contact has a presence subscription.
|
||||||
|
* @since 4.2
|
||||||
|
*/
|
||||||
|
public boolean canSeeMyPresence() {
|
||||||
|
switch (getType()) {
|
||||||
|
case from:
|
||||||
|
case both:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we are subscribed to the contact's presence. If <code>true</code> then the contact has allowed us to
|
||||||
|
* receive presence information.
|
||||||
|
*
|
||||||
|
* @return true if we are subscribed to the contact's presence.
|
||||||
|
* @since 4.2
|
||||||
|
*/
|
||||||
|
public boolean canSeeHisPresence() {
|
||||||
|
switch (getType()) {
|
||||||
|
case to:
|
||||||
|
case both:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
if (getName() != null) {
|
if (getName() != null) {
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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.smack.roster;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.BareJid;
|
||||||
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
|
public class RosterUtil {
|
||||||
|
|
||||||
|
public static void waitUntilOtherEntityIsSubscribed(Roster roster, BareJid otherEntity, long timeoutMillis)
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
Date deadline = new Date(System.currentTimeMillis() + timeoutMillis);
|
||||||
|
waitUntilOtherEntityIsSubscribed(roster, otherEntity, deadline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void waitUntilOtherEntityIsSubscribed(Roster roster, final BareJid otherEntity, Date deadline)
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
final Lock lock = new ReentrantLock();
|
||||||
|
final Condition maybeSubscribed = lock.newCondition();
|
||||||
|
RosterListener rosterListener = new AbstractRosterListener() {
|
||||||
|
private void signal() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
// No need to use signalAll() here.
|
||||||
|
maybeSubscribed.signal();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void entriesAdded(Collection<Jid> addresses) {
|
||||||
|
signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void entriesUpdated(Collection<Jid> addresses) {
|
||||||
|
signal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
roster.addRosterListener(rosterListener);
|
||||||
|
|
||||||
|
boolean stillWaiting = true;
|
||||||
|
// Using the example code pattern from Condition.awaitUntil(Date) javadoc.
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
while (!roster.isSubscribedToMyPresence(otherEntity)) {
|
||||||
|
if (!stillWaiting) {
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
|
stillWaiting = maybeSubscribed.awaitUntil(deadline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
// Make sure the listener is removed, so we don't leak it.
|
||||||
|
roster.removeRosterListener(rosterListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ dependencies {
|
||||||
compile project(':smack-java7')
|
compile project(':smack-java7')
|
||||||
compile project(':smack-tcp')
|
compile project(':smack-tcp')
|
||||||
compile project(':smack-extensions')
|
compile project(':smack-extensions')
|
||||||
|
compile project(':smack-experimental')
|
||||||
compile 'org.reflections:reflections:0.9.9-RC1'
|
compile 'org.reflections:reflections:0.9.9-RC1'
|
||||||
compile 'eu.geekplace.javapinning:java-pinning-java7:1.1.0-alpha1'
|
compile 'eu.geekplace.javapinning:java-pinning-java7:1.1.0-alpha1'
|
||||||
compile "junit:junit:$junitVersion"
|
compile "junit:junit:$junitVersion"
|
||||||
|
|
|
@ -16,10 +16,13 @@
|
||||||
*/
|
*/
|
||||||
package org.igniterealtime.smack.inttest;
|
package org.igniterealtime.smack.inttest;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public abstract class AbstractSmackIntTest {
|
public abstract class AbstractSmackIntTest {
|
||||||
|
|
||||||
protected static final Logger LOGGER = Logger.getLogger(AbstractSmackIntTest.class.getName());
|
protected static final Logger LOGGER = Logger.getLogger(AbstractSmackIntTest.class.getName());
|
||||||
|
|
||||||
|
protected static final Random INSECURE_RANDOM = new Random();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,11 @@ public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest
|
||||||
*/
|
*/
|
||||||
protected final XMPPConnection conTwo;
|
protected final XMPPConnection conTwo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The third connection.
|
||||||
|
*/
|
||||||
|
protected final XMPPConnection conThree;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An alias for the first connection {@link #conOne}.
|
* An alias for the first connection {@link #conOne}.
|
||||||
*/
|
*/
|
||||||
|
@ -42,6 +47,7 @@ public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest
|
||||||
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment environment) {
|
||||||
this.connection = this.conOne = environment.conOne;
|
this.connection = this.conOne = environment.conOne;
|
||||||
this.conTwo = environment.conTwo;
|
this.conTwo = environment.conTwo;
|
||||||
|
this.conThree = environment.conThree;
|
||||||
if (environment.configuration.replyTimeout > 0) {
|
if (environment.configuration.replyTimeout > 0) {
|
||||||
this.defaultTimeout = environment.configuration.replyTimeout;
|
this.defaultTimeout = environment.configuration.replyTimeout;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -53,6 +53,10 @@ public final class Configuration {
|
||||||
|
|
||||||
public final String accountTwoPassword;
|
public final String accountTwoPassword;
|
||||||
|
|
||||||
|
public final String accountThreeUsername;
|
||||||
|
|
||||||
|
public final String accountThreePassword;
|
||||||
|
|
||||||
public final boolean debug;
|
public final boolean debug;
|
||||||
|
|
||||||
public final Set<String> enabledTests;
|
public final Set<String> enabledTests;
|
||||||
|
@ -63,7 +67,7 @@ public final class Configuration {
|
||||||
|
|
||||||
private Configuration(DomainBareJid service, String serviceTlsPin, SecurityMode securityMode, int replyTimeout,
|
private Configuration(DomainBareJid service, String serviceTlsPin, SecurityMode securityMode, int replyTimeout,
|
||||||
boolean debug, String accountOneUsername, String accountOnePassword, String accountTwoUsername,
|
boolean debug, String accountOneUsername, String accountOnePassword, String accountTwoUsername,
|
||||||
String accountTwoPassword, Set<String> enabledTests, Set<String> disabledTests,
|
String accountTwoPassword, String accountThreeUsername, String accountThreePassword, Set<String> enabledTests, Set<String> disabledTests,
|
||||||
Set<String> testPackages) {
|
Set<String> testPackages) {
|
||||||
this.service = Objects.requireNonNull(service,
|
this.service = Objects.requireNonNull(service,
|
||||||
"'service' must be set. Either via 'properties' files or via system property 'sinttest.service'.");
|
"'service' must be set. Either via 'properties' files or via system property 'sinttest.service'.");
|
||||||
|
@ -83,6 +87,8 @@ public final class Configuration {
|
||||||
this.accountOnePassword = accountOnePassword;
|
this.accountOnePassword = accountOnePassword;
|
||||||
this.accountTwoUsername = accountTwoUsername;
|
this.accountTwoUsername = accountTwoUsername;
|
||||||
this.accountTwoPassword = accountTwoPassword;
|
this.accountTwoPassword = accountTwoPassword;
|
||||||
|
this.accountThreeUsername = accountThreeUsername;
|
||||||
|
this.accountThreePassword = accountThreePassword;
|
||||||
this.enabledTests = enabledTests;
|
this.enabledTests = enabledTests;
|
||||||
this.disabledTests = disabledTests;
|
this.disabledTests = disabledTests;
|
||||||
this.testPackages = testPackages;
|
this.testPackages = testPackages;
|
||||||
|
@ -110,6 +116,10 @@ public final class Configuration {
|
||||||
|
|
||||||
private String accountTwoPassword;
|
private String accountTwoPassword;
|
||||||
|
|
||||||
|
public String accountThreeUsername;
|
||||||
|
|
||||||
|
public String accountThreePassword;
|
||||||
|
|
||||||
private boolean debug;
|
private boolean debug;
|
||||||
|
|
||||||
private Set<String> enabledTests;
|
private Set<String> enabledTests;
|
||||||
|
@ -153,11 +163,13 @@ public final class Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setUsernamesAndPassword(String accountOneUsername, String accountOnePassword,
|
public Builder setUsernamesAndPassword(String accountOneUsername, String accountOnePassword,
|
||||||
String accountTwoUsername, String accountTwoPassword) {
|
String accountTwoUsername, String accountTwoPassword, String accountThreeUsername, String accountThreePassword) {
|
||||||
this.accountOneUsername = accountOneUsername;
|
this.accountOneUsername = StringUtils.requireNotNullOrEmpty(accountOneUsername, "accountOneUsername must not be null or empty");
|
||||||
this.accountOnePassword = accountOnePassword;
|
this.accountOnePassword = StringUtils.requireNotNullOrEmpty(accountOnePassword, "accountOnePassword must not be null or empty");
|
||||||
this.accountTwoUsername = accountTwoUsername;
|
this.accountTwoUsername = StringUtils.requireNotNullOrEmpty(accountTwoUsername, "accountTwoUsername must not be null or empty");
|
||||||
this.accountTwoPassword = accountTwoPassword;
|
this.accountTwoPassword = StringUtils.requireNotNullOrEmpty(accountTwoPassword, "accountTwoPasswordmust not be null or empty");
|
||||||
|
this.accountThreeUsername = StringUtils.requireNotNullOrEmpty(accountThreeUsername, "accountThreeUsername must not be null or empty");
|
||||||
|
this.accountThreePassword = StringUtils.requireNotNullOrEmpty(accountThreePassword, "accountThreePassword must not be null or empty");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +225,7 @@ public final class Configuration {
|
||||||
|
|
||||||
public Configuration build() {
|
public Configuration build() {
|
||||||
return new Configuration(service, serviceTlsPin, securityMode, replyTimeout, debug, accountOneUsername,
|
return new Configuration(service, serviceTlsPin, securityMode, replyTimeout, debug, accountOneUsername,
|
||||||
accountOnePassword, accountTwoUsername, accountTwoPassword, enabledTests, disabledTests,
|
accountOnePassword, accountTwoUsername, accountTwoPassword, accountThreeUsername, accountThreePassword, enabledTests, disabledTests,
|
||||||
testPackages);
|
testPackages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,7 +264,9 @@ public final class Configuration {
|
||||||
String accountOnePassword = properties.getProperty("accountOnePassword");
|
String accountOnePassword = properties.getProperty("accountOnePassword");
|
||||||
String accountTwoUsername = properties.getProperty("accountTwoUsername");
|
String accountTwoUsername = properties.getProperty("accountTwoUsername");
|
||||||
String accountTwoPassword = properties.getProperty("accountTwoPassword");
|
String accountTwoPassword = properties.getProperty("accountTwoPassword");
|
||||||
builder.setUsernamesAndPassword(accountOneUsername, accountOnePassword, accountTwoUsername, accountTwoPassword);
|
String accountThreeUsername = properties.getProperty("accountThreeUsername");
|
||||||
|
String accountThreePassword = properties.getProperty("accountThreePassword");
|
||||||
|
builder.setUsernamesAndPassword(accountOneUsername, accountOnePassword, accountTwoUsername, accountTwoPassword, accountThreeUsername, accountThreePassword);
|
||||||
|
|
||||||
builder.setDebug(properties.getProperty("debug"));
|
builder.setDebug(properties.getProperty("debug"));
|
||||||
builder.setEnabledTests(properties.getProperty("enabledTests"));
|
builder.setEnabledTests(properties.getProperty("enabledTests"));
|
||||||
|
@ -262,7 +276,7 @@ public final class Configuration {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static File findPropertiesFile() throws IOException {
|
private static File findPropertiesFile() {
|
||||||
List<String> possibleLocations = new LinkedList<>();
|
List<String> possibleLocations = new LinkedList<>();
|
||||||
possibleLocations.add("properties");
|
possibleLocations.add("properties");
|
||||||
String userHome = System.getProperty("user.home");
|
String userHome = System.getProperty("user.home");
|
||||||
|
|
|
@ -24,14 +24,17 @@ public class SmackIntegrationTestEnvironment {
|
||||||
|
|
||||||
public final XMPPTCPConnection conTwo;
|
public final XMPPTCPConnection conTwo;
|
||||||
|
|
||||||
|
public final XMPPTCPConnection conThree;
|
||||||
|
|
||||||
public final String testRunId;
|
public final String testRunId;
|
||||||
|
|
||||||
public final Configuration configuration;
|
public final Configuration configuration;
|
||||||
|
|
||||||
SmackIntegrationTestEnvironment(XMPPTCPConnection conOne, XMPPTCPConnection conTwo, String testRunId,
|
SmackIntegrationTestEnvironment(XMPPTCPConnection conOne, XMPPTCPConnection conTwo, XMPPTCPConnection conThree, String testRunId,
|
||||||
Configuration configuration) {
|
Configuration configuration) {
|
||||||
this.conOne = conOne;
|
this.conOne = conOne;
|
||||||
this.conTwo = conTwo;
|
this.conTwo = conTwo;
|
||||||
|
this.conThree = conThree;
|
||||||
this.testRunId = testRunId;
|
this.testRunId = testRunId;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue