Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@
**/.key
**/db
**/nodes.json
**/nodes*.zip
**/test.json
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

## Overview

This repository contains a Java SDK for creating [DSA](http://iot-dsa.org) links.
learn about the DSA architecture, please visit [this page](http://iot-dsa.org/get-started/how-dsa-works).
This repository contains a Java SDK for creating [DSA](http://iot-dsa.org) links. to learn about
the DSA architecture, please visit [this page](http://iot-dsa.org/get-started/how-dsa-works).

## Contents
## Modules

- **/dslink-core** - The APIs used to build new links.
- **/dslink-link-template** - Can be copied and modified to create a new dslink.
- **/dslink-java-template** - Can be copied to create a new dslink.
- **/dslink-websocket-standalone** - Used by links that run in their own process rather
than in a container which provides it's own websocket implementation.
than in a container which provides it's a different websocket implementation.

## Link Development

Expand Down
66 changes: 42 additions & 24 deletions docs/DeveloperGuide.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,62 @@
# DSLink Java Developer Guide

[Home](https://github.com/iot-dsa-v2/dslink-java) - [Javadoc](https://iot-dsa-v2.github.io/dslink-java/javadoc/)
[Home](https://github.com/iot-dsa-v2/sdk-dslink-java) - [Javadoc](https://iot-dsa-v2.github.io/sdk-dslink-java/javadoc/)

The purpose of this document is to guide the reader through the development of DSA links.
Developers will build links using the org.iot.dsa.* packages found in
dslink-java/modules/core/dslink-core.
## Warning

Only use org.iot.dsa APIs, do not use or depend on anything in the com.* packages.

## Overview

The purpose of this document is to guide the reader through the development of Java DSA links using
this SDK. Developers will build links using the org.iot.dsa.* packages found in
sdk-dslink-java/dslink-core.

Key objectives of the SDK:
Key objectives of this SDK:

- Pluggable architecture:
- Protocol independence. Primarily to support DSA V1 and V2.
- Transport independence. Websockets, plain sockets, http, and whatever else comes along.
- Support multiple links in the same process.
- Support JDK 1.6 for Distech.
- High performance for activities such as video streaming.
- 3rd party library independence. Some environments provide transport libraries while others
do not. SLF4J and Netty were explicitly bound to the original SDK but can not be used in Niagara.
- Support JDK 1.6 for Distech Controls.
- High performance for video streaming.
- 3rd party library independence. Some environments such as Niagara provide transport libraries
while others do not. SLF4J and Netty were explicitly bound to the original SDK but can not be
used in Niagara because of it's strict Security Manager.

## Warning
There are three ways to create a link.

Only use org.iot.dsa APIs, do not use or depend on anything in the com.* packages.
1. The easy way. Use nodes and values defined in org.iot.dsa.node. You will get
free configuration persistence and DSA protocol translation.

## Overview
2. The hard way. Implement your own org.iot.dsa.dslink.DSResponder.

3. A combination of 1 and 2.

## Creating Links the Easy Way

1. Boiler plate. Copy the dslink-java-template module from this repo. It has everything needed
to create a standalone link. It's README talks about what needs to be modified.

2. Create a root node. This node should subclass org.iot.dsa.dslink.DSRootNode. The main class
in the template module already does this.

3. Create nodes and values specific to your link's functionality.

### Project Boiler Plate

The dslink-java-template subproject in this repository can be copied to make a standalone link
repository.

Distributed Services Architecture (DSA), is an open source IoT platform that facilitates device
inter-communication, logic and applications at every layer of the Internet of Things
infrastructure. The objective is to unify the disparate devices, services and applications
into a structured and adaptable real-time data model. The premise of the open source DSA
initiative is to build a community of manufacturers, makers and solution providers that will
contribute to an ever-expanding library of Distributed Service Links which allow protocol
translation and data integration to and from 3rd party data-sources.
### Create a Root Node

From the developer's perspective a link is composed of the following:
The root node type is specified in dslink.json

- The root DSLink object.
- The connection to the upstream broker.
- A node tree representing functionality such a protocol drivers and applications.
### Creating Nodes and Values

## Link Structure
## Link

This package defines a data model that supports persistent
There are a few key classes / interfaces that define the general structure of a link and the SDK.

- Link (org.iot.dsa.dslink.DSLink)
Expand Down
17 changes: 13 additions & 4 deletions dslink-core/src/main/java/org/iot/dsa/dslink/DSLink.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,18 @@
import org.iot.dsa.util.DSException;

/**
* Represents an upstream connection, a node hierarchy, and manages the lifecycle of both. <p> Links
* are created with DSLinkConfig object. The main method of the process is responsible for creating
* the config. After instantiation, the link should call DSLink.start() <p> Lifecycle: TODO
* Represents an upstream connection, a node hierarchy, and manages the lifecycle of both.
*
* <p>
*
* Links are created with DSLinkConfig object. The main method of the process is responsible for
* creating the config. After instantiation, the link should call DSLink.run()
*
* <p>
*
* Lifecycle:
*
* TODO
*
* @author Aaron Hansen
*/
Expand Down Expand Up @@ -80,7 +89,7 @@ public DSLink(DSLinkConfig config) throws Exception {
throw new IllegalStateException("Config missing the root node type");
}
config(config() ? "Root type: " + type : null);
DSNode tmp = (DSNode) Class.forName(type).newInstance();
DSNode tmp = (DSNode) Class.forName(type).newInstance();
if (!(tmp instanceof DSResponder)) {
throw new IllegalStateException("Root type not a responder: " + type);
}
Expand Down
56 changes: 4 additions & 52 deletions dslink-core/src/main/java/org/iot/dsa/dslink/DSLinkConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public class DSLinkConfig {
public static final String CFG_LOG_LEVEL = "log";
public static final String CFG_NODE_FILE = "nodes";
public static final String CFG_READ_TIMEOUT = "readTimeout";
public static final String CFG_ROOT_NAME = "rootName";
public static final String CFG_ROOT_TYPE = "rootType";
public static final String CFG_STABLE_DELAY = "stableDelay";
public static final String CFG_TRANSPORT_FACTORY = "transportFactory";
Expand All @@ -45,7 +44,6 @@ public class DSLinkConfig {
private File logFile;
private Level logLevel;
private File nodesFile;
private String rootName;
private String rootType;
private String token;
private File workingDir = new File(".");
Expand Down Expand Up @@ -263,22 +261,15 @@ public File getNodesFile() {
return nodesFile;
}

/**
* The name of the root node.
*/
public String getRootName() {
if (rootName == null) {
setRootName(getConfig(CFG_ROOT_NAME, null));
}
return rootName;
}

/**
* The type of the root node.
*/
public String getRootType() {
if (rootType == null) {
setRootType(getConfig(CFG_ROOT_TYPE, null));
rootType = getConfig(CFG_ROOT_TYPE, null);
if (rootType == null) {
throw new IllegalStateException("Missing rootType config.");
}
}
return rootType;
}
Expand Down Expand Up @@ -343,10 +334,6 @@ private void processParsed(String key, String value) {
setLinkName(value);
} else if (key.equals("--nodes")) {
setNodesFile(new File(value));
} else if (key.equals("--rootName")) {
setRootName(value);
} else if (key.equals("--rootType")) {
setRootType(value);
} else if (key.equals("--token")) {
setToken(value);
} else {
Expand Down Expand Up @@ -503,48 +490,13 @@ public DSLinkConfig setNodesFile(File file) {
return setConfig(CFG_NODE_FILE, file.getAbsolutePath());
}

/**
* Overrides dslink.json.
*/
public DSLinkConfig setRootType(Class arg) {
return setRootType(arg.getName());
}

/**
* Overrides dslink.json.
*/
public DSLinkConfig setRootName(String arg) {
rootName = arg;
return setConfig(CFG_ROOT_NAME, arg);
}

/**
* Overrides dslink.json.
*/
public DSLinkConfig setRootType(String arg) {
rootType = arg;
return setConfig(CFG_ROOT_TYPE, arg);
}

/**
* Overrides dslink.json.
*/
public DSLinkConfig setToken(String arg) {
return setConfig(CFG_AUTH_TOKEN, arg);
}

/**
* Validates that the configuration represents a viable link startup state. This only needs to
* be called if the public no-arg constructor is used.
*
* @throws IllegalStateException whose message will describe the problem.
*/
public void validate() {
if (getBrokerUri() == null) {
throw new IllegalStateException("Missing broker uri.");
}
}

/**
* Whether or not -h or --help was provided.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ public interface DSLinkSession {
*/
public boolean shouldEndMessage();

} //class
}
6 changes: 5 additions & 1 deletion dslink-core/src/main/java/org/iot/dsa/dslink/DSRootNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ public void onSet(InboundSetRequest request) {
}
DSNode parent = path.getParent();
DSInfo info = path.getInfo();
if (info.isReadOnly()) {
throw new DSRequestException("Not writable: " + getPath());
}
//TODO verify incoming permission
DSIValue value = info.getValue();
if (value == null) {
if (info.getDefaultObject() instanceof DSIValue) {
Expand All @@ -93,7 +97,7 @@ public void onSet(InboundSetRequest request) {
} else {
throw new DSRequestException("Cannot decode value: " + parent.getPath());
}
parent.put(info.getName(), value);
parent.onSet(info, value);
}

///////////////////////////////////////////////////////////////////////////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import org.iot.dsa.security.DSPermission;

/**
* Maps a request path into a node tree.
* Used by DSRootNode to handle an invoke request.
*
* @author Aaron Hansen
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
import org.iot.dsa.node.DSNode;

/**
* Subscribes to the target of a list request and updates the stream when changes are detected.
* Used by DSRootNode to subscribe to the target of a list request and update the stream when
* changes are detected.
*
* @author Aaron Hansen
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.iot.dsa.dslink.responder.InboundListRequest;

/**
* Maps a request path into a node tree.
* Used by DSRootNode to handle and list request.
*
* @author Aaron Hansen
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.iot.dsa.security.DSPermission;

/**
* Maps a request path into a node tree.
* Used by DSRootNode to handle a set request.
*
* @author Aaron Hansen
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.iot.dsa.node.DSQuality;

/**
* Maps a request path into a node tree.
* Used by DSRootNode to handle subscribe requests.
*
* @author Aaron Hansen
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import org.iot.dsa.node.DSString;

/**
* Maps a request path into a node tree.
* Used by DSRootNode to handle value subscriptions.
*
* @author Aaron Hansen
*/
Expand Down
14 changes: 14 additions & 0 deletions dslink-core/src/main/java/org/iot/dsa/node/DSNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import org.iot.dsa.dslink.responder.InboundSetRequest;
import org.iot.dsa.logging.DSLogger;
import org.iot.dsa.logging.DSLogging;
import org.iot.dsa.node.action.ActionInvocation;
Expand Down Expand Up @@ -562,6 +563,19 @@ public ActionResult onInvoke(DSInfo actionInfo, ActionInvocation invocation) {
throw new IllegalStateException("onInvoke not overridden");
}

/**
* Override point, called when a value child is being set by the responder. The default
* implementation calls put(info, value). If you throw an exception, an error will be
* reported to the requester.
*
* @param info The child being changed.
* @param value The new value.
* @see org.iot.dsa.dslink.DSResponder#onSet(InboundSetRequest)
*/
public void onSet(DSInfo info, DSIValue value) {
put(info, value);
}

/**
* Called when this container transitions from unsubscribed to subscribed, but is not called for
* subsequent subscribers.
Expand Down
Loading