Add (partial) support for IoT XEPs

That is XEP-0323, -0324, -0325, and -0347.

SMACK-727.
This commit is contained in:
Florian Schmaus 2016-07-20 20:57:04 +02:00
parent d1fe5c2933
commit b91978dcc4
110 changed files with 5395 additions and 40 deletions

View File

@ -55,6 +55,8 @@ debug=true
| accountOnePassword | Password of the first XMPP account |
| accountTwoUsername | Username 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 |
| enabledTests | List of enabled tests |
| disabledTests | List of disabled tests |

View File

@ -1,4 +1,4 @@
Smack Extensions User Manual
smackSmack Extensions User Manual
============================
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 |
|---------------------------------------------|----------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
| 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. |
| [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 |
| Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. |

View 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);
```

View File

@ -238,7 +238,11 @@ public final class ReconnectionManager {
// Makes a reconnection attempt
try {
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
// longer login automatically. So change this and the

View File

@ -25,13 +25,7 @@ public class EmptyResultIQ extends IQ {
public EmptyResultIQ(IQ request) {
this();
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());
initialzeAsResultFor(request);
}
@Override

View File

@ -215,6 +215,17 @@ public abstract class IQ extends Stanza {
*/
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}
* 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
* {@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.
* @deprecated use {@link #createErrorResponse(IQ, org.jivesoftware.smack.packet.XMPPError.Builder)} instead.
*/
@Deprecated
public static ErrorIQ createErrorResponse(final IQ request, final XMPPError error) {
return createErrorResponse(request, XMPPError.getBuilder(error));
}

View File

@ -73,6 +73,8 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
* @param type the type.
*/
public Presence(Type type) {
// Ensure that the stanza ID is set by calling super().
super();
setType(type);
}
@ -85,6 +87,8 @@ public final class Presence extends Stanza implements TypedCloneable<Presence> {
* @param mode the mode type for this presence update.
*/
public Presence(Type type, String status, int priority, Mode mode) {
// Ensure that the stanza ID is set by calling super().
super();
setType(type);
setStatus(status);
setPriority(priority);

View File

@ -23,6 +23,7 @@ import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import org.jivesoftware.smack.SmackException;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.Jid;
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) {
String valueString = parser.getAttributeValue("", name);
if (valueString == null)

View File

@ -238,6 +238,10 @@ public class XmlStringBuilder implements Appendable, CharSequence {
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,
* which will get formated with {@link XmppDateTime#formatXEP0082Date(Date)}.

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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";
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;