Using Orion Context Broker

Application Mashup (WireCloud) course @ http://edu.fiware.org

Presenter Notes

Using Orion Context Broker

Introduction

Presenter Notes

Introduction

As part of the FIWARE work, WireCloud has integrated support for accessing Orion Context Broker (reference implementation of the FIWARE's Pub/Sub Context Broker GE) instances from widgets/operators. In this tutorial we're going to learn how to use this support.

Presenter Notes

Using Orion Context Broker

Adding NGSI support to widgets and operators

Presenter Notes

Adding NGSI support to widgets and operators

First of all, widgets and operators wishing to use the JavaScript bindings provided by WireCloud for accessing the FIWARE NGSI Open RESTful API in order to seamlessly interoperate with the Orion Context Broker must add the NGSI feature as a requirement into their description files (config.xml files).

Presenter Notes

Adding NGSI support to widgets and operators

Using the XML description format

The following is an example of a widget description using the XML flavour of the Mashable Application Component Description Language:

<?xml version='1.0' encoding='UTF-8'?>
<widget xmlns="http://wirecloud.conwet.fi.upm.es/ns/macdescription/1" vendor="CoNWeT" name="observation-reporter" version="1.0">
  <details>
    <title>Observation Reporter</title>
    <authors>aarranz</authors>
    <email>aarranz@conwet.com</email>
    <image>images/catalogue.png</image>
    <smartphoneimage>images/smartphone.png</smartphoneimage>
    <description>Creates a new observation</description>
    <doc>http://www.envirofi.eu/</doc>
  </details>
  <requirements>
    <feature name="NGSI"/>
  </requirements>
  <wiring/>
  <contents src="index.html" contenttype="text/html" charset="utf-8" useplatformstyle="true"/>
  <rendering height="20" width="5"/>
</widget>

Presenter Notes

Adding NGSI support to widgets and operators

Using the RDF description format

The RDF/xml flavour of the same widget description is:

<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF
  xmlns:foaf="http://xmlns.com/foaf/0.1/"
  xmlns:wire="http://wirecloud.conwet.fi.upm.es/ns/widget#"
  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
  xmlns:usdl="http://www.linked-usdl.org/ns/usdl-core#"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:ns1="http://purl.org/goodrelations/v1#"
  xmlns:dcterms="http://purl.org/dc/terms/"
  xmlns:vcard="http://www.w3.org/2006/vcard/ns#"
>
  <wire:Widget rdf:about="http://wirecloud.conwet.fi.upm.es/ns/widget#CoNWeT/observation-reporter/1.0">
    <vcard:addr>
      <vcard:Work rdf:nodeID="Nb17ce611aa2645e488515f86eb855e53">
        <vcard:email>aarranz@conwet.com</vcard:email>
      </vcard:Work>
    </vcard:addr>
    <usdl:utilizedResource>
      <usdl:Resource rdf:about="index.html">
        <wire:codeCacheable>True</wire:codeCacheable>
      </usdl:Resource>
    </usdl:utilizedResource>
    <wire:hasPlatformWiring>
      <wire:PlatformWiring rdf:nodeID="Neecb97db81ed40859b8c04e935a9a9cc"/>
    </wire:hasPlatformWiring>
    <wire:displayName>Observation Reporter</wire:displayName>
    <wire:hasiPhoneImageUri rdf:resource="images/smartphone.png"/>
    <usdl:versionInfo>1.0</usdl:versionInfo>
    <usdl:hasProvider>
      <ns1:BusinessEntity rdf:nodeID="N9a6bf56577c741ac806997a80281afff">
        <foaf:name>CoNWeT</foaf:name>
      </ns1:BusinessEntity>
    </usdl:hasProvider>
    <wire:hasImageUri rdf:resource="images/catalogue.png"/>
    <wire:hasPlatformRendering>
      <wire:PlatformRendering rdf:nodeID="N713e5ea11dce4750a592c754c748def7">
        <wire:renderingHeight>20</wire:renderingHeight>
        <wire:renderingWidth>5</wire:renderingWidth>
      </wire:PlatformRendering>
    </wire:hasPlatformRendering>
    <wire:hasRequirement>
      <wire:Feature rdf:nodeID="N3cb336bd9b6243ecbf345c80442498f9">
        <rdfs:label>NGSI</rdfs:label>
      </wire:Feature>
    </wire:hasRequirement>
    <dcterms:title>observation-reporter</dcterms:title>
    <dcterms:description>Creates a new observation</dcterms:description>
    <dcterms:creator>
      <foaf:Person rdf:nodeID="Ndb72cb5a7f3844b29b72f304baaa14a7">
        <foaf:name>aarranz</foaf:name>
      </foaf:Person>
    </dcterms:creator>
  </wire:Widget>
</rdf:RDF>

Presenter Notes

Using Orion Context Broker

Creating connections to NGSI Context Brokers

Presenter Notes

Creating connections to NGSI Context Brokers

Before being able to make use of the NGSI API, you should create a Connection with the NGSI Context Broker you're going to use. This can be accomplished with the following code:

var ngsi_connection = new NGSI.Connection(ngsi_server[, options]);

Presenter Notes

Creating connections to NGSI Context Brokers

See the NGSI javascript API documentation for the full list of supported options but, as summary, the ngsi_proxy_url option is required for being able to create subscriptions handled by widgets/operators. Also, if you are connecting to a Orion Context Broker using the IdM authentication, you will need to pass the required authentication credentials. This can be accomplished in two ways:

  • Making use of the request_headers option and passing directly the required Authentication header
  • Making use of the use_user_fiware_token option to make the the NGSI API user the FIWARE's OAuth2 token of the current user (obtained by WireCloud from the IdM). Any request made by a connection using this option will fail if the current users doesn't have a valid token (take into account that anonymous users and users authenticated using other authentication backends fall into this category). If you're worried about security, take into account that the OAuth2 token is injected in the request by the WireCloud's proxy

Presenter Notes

Creating connections to NGSI Context Brokers

This is an example of NGSI connection creation using the resources available at FIWARE Lab:

var ngsi_connection = new NGSI.Connection('http://orion.lab.fiware.org:1026', {
    use_user_fiware_token: true,
    ngsi_proxy_url: 'https://ngsiproxy.lab.fiware.org'
});

Once created the connection, you will be able to use the NGSI API bindings (in the example, through the ngsi_connection variable).

Presenter Notes

Using Orion Context Broker

Making queries

Presenter Notes

Making queries

Queries are the most basic operations that can be executed in a Orion Context Broker. This operation can be accessed thought the query method of the connection object:

var entityIdList = [
    {type: 'Van', id: '.*', isPattern: true}
];
var attributeList = ['current_position'];
var options = {
    flat: true,
    onSuccess: function (data) {
        // data contains the obtained info
        // from the context broker
    }
};
ngsi_connection.query(entityIdList, attributeList, options);

Presenter Notes

Making queries

The first parameter is the list of entities you're interested on. In our case, we're interested in all Van entities. This is accomplished using the isPattern option that allows us to use a regular expression that matches with any id.

The second one is the list of attributes you're interested on. In our case, we're interested only in the current_position attribute. However, you can pass null or an empty list to indicate that you are interested in all the attributes of the selected entities.

Presenter Notes

Making queries

Finally, all the methods supports a last parameter called options that should be used to pass the callbacks and the extra options. Any method of NGSI.Connection support at least the following callbacks:

  • onSuccess is called when the request finishes successfully. The parameters passed to this callback depends on the invoked method. In the case of the query operation, the first parameter will contain the data returned after querying the context broker
  • onFailure is called when the request finish with errors
  • onComplete is called when the request finish regardless of whether the request is successful or not

Presenter Notes

Making queries

The query method also supports other extra options. The flat options is used for simplifying the data structure used for representing the returned data. This simplification relies in making the following assumptions about the returned entry set:

  • given an entity id there is only one value for the entity's type parameter
  • entities doesn't have attributes called id or type
  • entities have only an attribute with a given name
  • attribute types don't matter or are already known
  • attribute metadata don't matter or is already known

Presenter Notes

Making queries

For example, this is the value of the data parameter passed to the onSuccess callback when using the flat option:

 {
    "van1": {
        "id": "van1",
        "type": "Van",
        "current_position": "43.47557, -3.8048315"
    },
    "van2": {
        "id": "van2",
        "type": "Van",
        "current_position": "43.47258, -3.8026643"
    },
    "van3": {
        "id": "van3",
        "type": "Van",
        "current_position": "43.47866, -3.7991238"
    },
    "van4": {
        "id": "van4",
        "type": "Van",
        "current_position": "43.471214, -3.7994885"
    }
}

Presenter Notes

Making queries

Whereas this is the value of the data parameter when flat is false (default value):

 [
    {
        "entity": {
            "id": "van1",
            "type": "Van"
        },
        "attributes": [
            {
                "name": "current_position",
                "type": "coordinates",
                "contextValue": "43.47557, -3.8048315",
                "metadata": [{name: 'location', type: 'string', value: 'WGS84'}]
            }
        ]
    },
    {
        "entity": {
            "id": "van2",
            "type": "Van"
        },
        "attributes": [
            {
                "name": "current_position",
                "type": "coordinates",
                "contextValue": "43.47258, -3.8026643",
                "metadata": [{name: 'location', type: 'string', value: 'WGS84'}]
            }
        ]
    },
    {
        "entity": {
            "id": "van3",
            "type": "Van"
        },
        "attributes": [
            {
                "name": "current_position",
                "type": "coordinates",
                "contextValue": "43.47866, -3.7991238",
                "metadata": [{name: 'location', type: 'string', value: 'WGS84'}]
            }
        ]
    },
    {
        "entity": {
            "id": "van4",
            "type": "Van"
        },
        "attributes": [
            {
                "name": "current_position",
                "type": "coordinates",
                "contextValue": "43.471214, -3.7994885",
                "metadata": [{name: 'location', type: 'string', value: 'WGS84'}]
            }
        ]
    }
]

Presenter Notes

Making queries

Pagination

In addition to the flat option. The query method also support other options related to the pagination support found on Orion 0.14.0 and newer. These options are the limit, offset and details options. For example, the following code can be used for retrieving a first page containing (at most) 100 entities:

var options = {
    flat: true,
    limit: 100,
    onSuccess: function (data) {
        ....
    }
};
ngsi_connection.query(entityIdList, attributeList, options);

Presenter Notes

Making queries

Pagination

While this code will request the second page:

var options = {
    flat: true,
    limit: 100,
    offset: 100,
    onSuccess: function (data) {
        ....
    }
};
ngsi_connection.query(entityIdList, attributeList, options);

Presenter Notes

Making queries

Pagination

You can get the total number of matches using the details option:

var options = {
    flat: true,
    limit: 100,
    offset: 200,
    details: true,
    onSuccess: function (data, details) {
        // The total number of matches is stored in details.count
        ....
    }
};
ngsi_connection.query(entityIdList, attributeList, options);

Presenter Notes

Using Orion Context Broker

Creating subscriptions

Presenter Notes

Creating subscriptions

One of the most important operations provided by the context broker is the support for creating subscriptions, in this way our system can obtain "real time" notifications about the status of the entities of our system. Subscriptions are very similar to queries, the main difference between queries and subscriptions is that queries are synchronous operations. Moreover, the Orion Context Broker will send a first notification containing the data that would be returned for the equivalent query operation. This way, you will know that there is no gap between the current values and their notified changes.

Both widgets and operators can create subscriptions through the createSubscription method.

Presenter Notes

Creating subscriptions

The following example explains how to be notified about the changes of the position of the vans:

var entityIdList = [
    {type: 'Van', id: '.*', isPattern: true}
];
var attributeList = null;
var duration = 'PT3H';
var throttling = null;
var notifyConditions = [{
    type: 'ONCHANGE',
    condValues: ['current_position']
}];
var options = {
    flat: true,
    onNotify: function (data) {
        // called when the context broker sends a new notification
    },
    onSuccess: function (data) {
        ngsi_subscriptionId = data.subscriptionId;
    }
};
ngsi_connection.createSubscription(entityIdList, attributeList, duration, throttling, notifyConditions, options);

Presenter Notes

Creating subscriptions

In the previous example, this call to createSubscription will make the context broker call the onNotify function each time the current_position attribute of the entities of type Van is changed. You must take into account that the Orion Context Broker evaluates patterns at runtime, so using patterns you will be able to receive notification about new entities provided that the notify conditions are meet.

This subscription will expire after 3 hours, time from which the context broker will stop sending notifications. Anyway, widgets/operators can renew those subscriptions by using the updateSubscription method, even if they have expired. Subscriptions can be cancelled using the cancelSubscription method making the context broker release any info about the subscription. In any case, WireCloud will cancel any subscription automatically when widgets/operators are unloaded.

Presenter Notes

Creating subscriptions

As with the query operations, you can make use of the flat option when creating subscriptions. The assumptions made by the createSubscription method will be the same that the ones used by the query method, the only thing that changes is that this affects to the parameter passed to the notification callback instead to the success callback.

Presenter Notes

Creating subscriptions

As example, this is the value of the data parameter passed to the onNotify callback when using the flat option:

{
    "elements": {
        "van2": {
            "id": "van2",
            "type": "Van",
            "current_position": "43.47258, -3.8026643"
        },
        "van4": {
            "id": "van4",
            "type": "Van",
            "current_position": "43.471214, -3.7994885"
        }
    },
    "subscriptionId": "53708768286043030c116e2c",
    "originator": "localhost"
}

Presenter Notes

Creating subscriptions

Whereas this is the value of the data parameter when flat is false (default value):

{
    "elements": [
        {
            "entity": {
                "id": "van2",
                "type": "Van"
            },
            "attributes": [
                {
                    "name": "current_position",
                    "type": "coordinates",
                    "contextValue": "43.47258, -3.8026643"
                }
            ]
        },
        {
            "entity": {
                "id": "van4",
                "type": "Van"
            },
            "attributes": [
                {
                    "name": "current_position",
                    "type": "coordinates",
                    "contextValue": "43.471214, -3.7994885"
                }
            ]
        }
    },
    "subscriptionId": "53708768286043030c116e2c",
    "originator": "localhost"
}

Presenter Notes

Using Orion Context Broker

Creating entities and updating their attributes

Presenter Notes

Creating entities and updating their attributes

Widgets and operator can update entities using the updateAttributes and addAttributes methods. The updateAttributes and addAttributes methods use the same format for their parameters, the main difference is that addAttribute method will create new attributes/entities if needed whereas updateAttributes will fail if the referred entities/attributes didn't exist.

Presenter Notes

Creating entities and updating their attributes

For example, the following code updates the attribute position of the van1 entity if it exists, or creates the attribute or the entity if one of them don't exist:

ngsi_connection.addAttributes([{
        entity: {id: 'van1', type: 'Van'},
        attributes: [
            {
                type: 'string',
                name: 'current_position',
                contextValue: coordinates
            }
        ]
    }], {
        onSuccess: function (accepted_changes, unaccepted_changes) {
            // The Orion Context Broker processed the request successfully
            if (unaccepted_changes.length === 0) {
                // Van created/updated successfully
                ...
            } else {
                // Something went wrong
            }
        }.bind(this),
        onFailure: function (error) {
            // General failure when creating/updating the van
        },
        onComplete: function () {
            //
        }.bind(this)
    }
);

Presenter Notes

Creating entities and updating their attributes

The response_data parameter of the onSuccess callback is a summary of the accepted changes as returned by the Orion Context Broker. This info can normally be ignored, as it will be very similar to the one provided to the updateAttributes/addAttribute methods when the request ends successfully. If everything goes ok, the unaccepted_changes parameter will contain an empty array. If something goes wrong, the unaccepted_changes parameter will contain all the info about what changes were rejected. It's very important to take this into account as the onFailure callback won't be called for reporting unaccepted changes as they are treated individually by the Orion Context Broker.

Presenter Notes

Creating entities and updating their attributes

For example, if we execute the following code:

ngsi_connection.updateAttributes([
        {
            'entity': {type: 'City', id: 'Madrid'},
            'attributes': [
                {name: 'position', type: 'coords', contextValue: '40.418889, -3.691944'}
            ]
        },
        {
            'entity': {type: 'Point', id: 'A'},
            'attributes': [
                {name: 'mobile_phone', type: 'string', contextValue: '0034223456789'}
            ]
        }
    ],
    ...
    );

Presenter Notes

Creating entities and updating their attributes

Giving the fact both Madrid and A entities exit but only the position attribute exists, the value of the accepted_changes will be:

[
    {
        entity: {id: 'Madrid', type: 'City'},
        attributes: [
            {name: 'position', type: 'coords'}
        ]
    }
]

Presenter Notes

Creating entities and updating their attributes

Whereas the value of the unaccepted_changes parameters will be something similar to this:

[
    {
        entity: {id: 'A', type: 'Point'},
        attributes: [
            {name: 'mobile_phone', type: 'string'}
        ],
        statusCode: {
            code: 472,
            reasonPhrase: 'request parameter is invalid/not allowed',
            details : 'action: UPDATE - entity: (A, Point) - offending attribute: mobile_phone'
        }
    }
]

Presenter Notes

Using Orion Context Broker

Using Orion's geolocation capabilities

Presenter Notes

Using Orion's geolocation capabilities

The following code snippet shows an example of how to create a position attribute indicating that it will be used for defining the location of the entity:

ngsi_connection.addAttributes([
        {
            entity: {type: 'City', id: 'Madrid'},
            attributes: [
                {
                    name: 'position',
                    type: 'coords',
                    contextValue: '40.418889, -3.691944',
                    metadata: [
                        {name: 'location', type: 'string', value: 'WGS84'}
                    ]
                }
            ]
        }
    ],
    ...
    );

Presenter Notes

Using Orion's geolocation capabilities

After which you can issue geo-located queries. For example:

connection.query([
        {type: 'City', id: '.*', isPattern: true}
    ],
    null,
    {
        restriction: {
            scopes: [
                {
                    type: "FIWARE_Location",
                    value: {
                        circle: {
                            centerLatitude: "40.418889",
                            centerLongitude: "-3.691944",
                            radius: "14000"
                        }
                    }
                }
            ]
        },
        ...
     });

Presenter Notes

Using Orion's geolocation capabilities

Or:

connection.query([
        {type: 'Point', id: '.*', isPattern: true}
    ],
    null,
    {
        restriction: {
            scopes: [
                {
                    type : "FIWARE_Location",
                    value : {
                        polygon: {
                            vertices: [
                                { latitude: "0", longitude: "0" },
                                { latitude: "0", longitude: "6" },
                                { latitude: "6", longitude: "0" }
                            ],
                            inverted: true
                        }
                    }
                }
            ]
        },
        ...
    });

Presenter Notes

Using Orion Context Broker

A Real Example

Presenter Notes

A Real Example

To check how NGSI works, an example using this feature is provided. If you want to see it running you have to upload the following mashup into WireCloud:

This mashup uses the following components:

Once uploaded, you will be able to create new workspaces using this mashup as template. Take into account that this example is meant to work on FIWARE Lab.

Another source of examples is the OrionStarterKit offering available at the FIWARE Lab's Store containing all the generic widgets and operators related to the Orion Context Broker and several example mashups.

Presenter Notes

A Real Example

If everything is ok, you will see a map as the following one, with the location of some lampposts in the city of Santander.

Presenter Notes

Thanks!

Presenter Notes