DevLost

A developer lost in the mountains

Gateway Data Handling EspR4Fast GE: a tip to delete a single event sink

We are playing with this GE from a while and we found that there is not a quick way to delete/modify a single event sink.

What to do then?

We found two ways, but both require additional operations:

1) reset the full chain of CEP app with "/admin/espr4fastdata" REST call, but this requires to registrate again all the event types, statements etc.

2) delete the related statement, recreate it and recreate the event sink

Orion Context Broker: delete a subscription without having the ID

I was testing the subscription/notification feature of Orion Context Broker (https://forge.fiware.org/plugins/mediawiki/wiki/fiware/index...)  and I made a number of subscriptions without taking note of the ID of the new subscription returned by the system.

Soon I went in a situation where Orion was firing a lot of notifications  to the Cygnus connector that I had configured.

I wanted to delete most of the subscriptions, but the REST call available, i.e. unsubscribeContext, requires that you know the id of the subscription. What to do then?

Official documentation suggests, as ultimate remedy, to delete the entire database: (https://forge.fiware.org/plugins/mediawiki/wiki/fiware/index.php/Publish/Subscribe_Broker...).

But I was reluctant to follow this way and then I looked for a mongodb admnistration and found this umongo:

http://edgytech.com/umongo/

The installation is trivial: just download the zip file, unzip and launch launch-umongo.sh

I loaded the default instance of mongodb in my linux box and started to look for an id under orion databases; the subscriptions are in the csubs collection:



Then I created a simple REST call in SoapUI to unsubscribe the subscription with that ID:


Freeboard and Orion Context Broker - a workaround for the CORS issue

Orion Context Broker is an open source component belonging to the wide archipelago of FIWARE components available on this site.

In particular, if you are developing a Data/Context scenario, the Orion Context Broker plays the role of a component in the architecture able to mediate between consumer producers (e.g. sensors) and the context consumer applications (e.g. an smartphone applications taking advantage of the context information provided by the sensors). It runs as a deamon process providing NGSI9 and NGSI10 interfaces. Full documentation here.

When I started to work with Orion Context Broker for my SAT project, I looked around to find a quick & stylish solution to display data stored in the DB used by Orion CB (btw mongoDB); soon I found Freeboard, a nice open source dashboard for the Internet of Things and a "ready to work" plugin for Freeboard that is able to connect it to an Orion instance: Freeboard-Orion-Plugin.

All right? All OK? No, unfortunately the plugin did not work in all my attempts . The fact is that, behind the scene, the freeboard plugin makes a cross-domain Ajax call to my Orion instance and this is inhibited by design due to browser-enforced, same-origin security policies for JavaScript.

What to do then ? Recently W3C came out with the Cross Origin Resource Sharing (CORS) specification, a mechanism that works by adding HTTP headers to cross-domain HTTP requests and responses. The headers indicate the origin of the request and the server has to inform via headers in the response whether it will serve resources to this origin.  This exchange of headers is what makes CORS a secure mechanism totaly transparent to the user since the headers are built by the browser and the server.

So, why it did not worked in my case?

Just because Orion context Broker server does not support CORS at the moment:

http://stackoverflow.com/questions/28246116/no-access-control-allow-origin-header-is-present-on-orion-context-broker

https://github.com/telefonicaid/fiware-orion/issues/501

there is more than a solution to get rid of the problem. You may create for instance a proxy in PHP:

https://github.com/inter-coder/Orion-Web-Proxy-for-Cross-Domain


My Solution:

I followed a different way; I installed Apache httpd on the same machine of the Orion instance and I used it as a proxy.

To do so just follow the steps below:

1) Edit httpd.conf file in /etc/httpd/conf and instruct Apache to load proxy module add the following lines at the end:

LoadModule  proxy_module         modules/mod_proxy.so
LoadModule  proxy_http_module    modules/mod_proxy_http.so
LoadModule  headers_module       modules/mod_headers.so
LoadModule  deflate_module       modules/mod_deflate.so

2) Add proxy permissions as your choice:

<Proxy *>
   Order deny,allow
Allow from all
</proxy>

3) Add some rules to instruct Apache to intercept NGSI calls to Orion:

ProxyPass /v1/queryContext http://127.0.0.1:1026/v1/queryContext
ProxyPassReverse /v1/querycontext http://127.0.0.1:1026/v1/queryContext
ProxyPass /v1/registerContext http://127.0.0.1:1026/v1/registerContext
ProxyPassReverse /v1/registerContext http://127.0.0.1:1026/v1/registerContext
ProxyPass /v1/updateContext http://127.0.0.1:1026/v1/updateContext
ProxyPassReverse /v1/updateContext http://127.0.0.1:1026/v1/updateContext

4) Save conf file and restart your httpd server


Fabric: extend Image class

Recently I came up with the need to extend Image class of Fabric js lib. I had to keep synchronized two different Fabric Canvases, with different scale.

In the code snippet below, fabric.TavImage extends fabric.Image. AddToCanvases function adds an instance of TavImage to one canvas, then clones the object and adds it, scaled, to another canvas.

// 
//  TavImage
//
fabric.TavImage = fabric.util.createClass(fabric.Image, {

    type: 'tavImage',

    initialize: function (element, options) {
        options || (options = {});

        this.callSuper('initialize', element, options);
        this.set('scaleFrontCanvas', options.scaleFrontCanvas || '');
        this.set('scaleHiddenCanvas', options.scaleHiddenCanvas || '');
        this.set('id', options.id || '');
        this.set('objFrontCloned', options.objFrontCloned || '');
        this.set('trasfParams', options.trasfParams || '');
        this.set('isBaseImage', options.isBaseImage || false);
        this.set('scaleFactor', options.scaleFactor || '');
    },

    toObject: function () {
        return fabric.util.object.extend(this.callSuper('toObject'), {
            scaleFrontCanvas: this.get('scaleFrontCanvas'),
            scaleHiddenCanvas: this.get('scaleHiddenCanvas'),
            id: this.get('id'),
            objFrontCloned: this.get('objFrontCloned'),
            trasfParams: this.get('trasfParams'),
            isBaseImage: this.get('isBaseImage'),
            scaleFactor: this.get('scaleFactor')
        });
    },

    _render: function (ctx) {
        this.callSuper('_render', ctx);
    },

   
    addToCanvases: function (hiddenCanvas, frontCanvas) {

        hiddenCanvas.hiddenObjectsCount += 1;

        // check if it is not already in canvs
        var objects = hiddenCanvas.getObjects();
        for (var i in objects) {
            if (objects[i].get('id') == this.id)
                return;
        }


        // add to frontCanvas
        this.addToFrontCanvas(frontCanvas);
        
        // add to hidden Canvas
        this.addToHiddenCanvas(hiddenCanvas);
        
    },

    addToFrontCanvas: function (frontCanvas) {

        // clone object
        this.objFrontCloned = fabric.util.object.clone(this);
        this.objFrontCloned.scaleX = this.scaleFrontCanvas || this.scaleX;
        this.objFrontCloned.scaleY = this.scaleFrontCanvas || this.scaleY;

        frontCanvas.add(this.objFrontCloned);

        // center base image layer
        if (this.isBaseImage == true) {
            this.objFrontCloned.center();
        }

        this.objFrontCloned.setCoords();
    },

    addToHiddenCanvas: function (hiddenCanvas) {
        // scale to hiddenCanvas
        this.scaleX = this.scaleHiddenCanvas || this.scaleX;
        this.scaleY = this.scaleHiddenCanvas || this.scaleY;

        hiddenCanvas.add(this);


        // center base image layer
        if (this.isBaseImage == true) {
            //this.objFrontCloned.center();
            //this.objFrontCloned.setCoords();
        }
        else {
            this.updateCoordsForHiddenCanvas();
            //this.updateScaleForHiddenCanvas();
        }

    },

    updateCoordsForHiddenCanvas: function () {

        this.left = Math.round(this.trasfParams.s + 1/this.scaleFrontCanvas * (this.objFrontCloned.left - this.trasfParams.s1));
        this.top = Math.round(this.trasfParams.t + 1/this.scaleFrontCanvas * (this.objFrontCloned.top - this.trasfParams.t1));

        this.setCoords();
    },

    updateScaleForHiddenCanvas: function () {
        if(this.scaleFactor == '')
            this.scaleFactor = this.objFrontCloned.scaleX;
        this.scaleX = this.objFrontCloned.scaleX / this.scaleFactor;
        this.scaleY = this.objFrontCloned.scaleY / this.scaleFactor;
        
        this.setCoords();
    }
   
});

/**
   * Creates an instance of fabric.Image from an URL string
   * @static
   * @param {String} url URL to create an image from
   * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument)
   * @param {Object} [imgOptions] Options object
   */
fabric.TavImage.fromURL = function (url, callback, imgOptions) {
    fabric.util.loadImage(url, function (img) {
        callback(new fabric.TavImage(img, imgOptions));
    }, null, imgOptions && imgOptions.crossOrigin);
};