Source: org/terraswarm/accessor/accessors/web/services/HostCompatibility.js

/** Check Host Compatability of an accessor by performing 
 *  a SPARQL query on a semantic repository such as GraphDB.
 * 
 *  This accessor works by querying an Accessor and Host Ontology for the modules
 *  required by the accessor and the modules implemented by the given host.
 *
 *  See SemanticRepositoryQuery accessor documenation for additional documentation
 *  on SPARQL queries and setting up a semantic repository.
 *
 *  This accessor's image has a Creative Commons license and is from
 *  https://pixabay.com/en/puzzle-pieces-jigsaw-piece-concept-308908/
 *
 *  @accessor services/HostCompatability
 *  @author Matt Weber
 *  @version $$Id: SemanticRepository.js 1725 2017-05-19 22:59:11Z cxh $$
 *  @input {string} accessorName The full name of the accessor (including the directory 
 *  and .js at the end). Eg. Services/HostCompatability.js.
 *  @parameter {string} accessorHostName The name of the accessor host to be compared with accessorName.
 *   The special value 'ThisHost' will cause this accessor to use the getHostName function to determine
 *   the name of the accessor host for comparison.
 *  @parameter {string} host The URL for the semantic repository.
 *  @parameter {string} port The port for the semantic repository.
 *  @parameter {string} repositoryName The name of the particular repository on the host.
 *  @parameter {int} timeout The amount of time (in milliseconds) to wait for a response
 *   before triggering a null response and an error. This defaults to 20000.
 *  @output {boolean} compatible True if all the accessor's required modules are
 *   implemented by the given host. False otherwise.
 */


// Stop extra messages from jslint and jshint.  Note that there should
// be no space between the / and the * and global. See
// https://chess.eecs.berkeley.edu/ptexternal/wiki/Main/JSHint */
/*globals addInputHandler, addInputParameter, console, error, exports, extend, input, get, getParameter, getResource, output, parameter, send */
/*jshint globalstrict: true*/
'use strict';
 
 /** Set up the accessor by defining the inputs and outputs.
 */
exports.setup = function () {
    this.extend('services/SemanticRepositoryQuery');
    this.input('accessorName', {
        'type': 'string',
        'value': 'services/HostCompatability.js'
    });

    this.output('compatible', {
        'type': 'boolean'
    });

    this.parameter('accessorHostName', {
        'type': 'string',
        'options': ['ThisHost', 'Browser', 'Cordova', 'Duktape', 'Nashorn', 'Node'],
        'value': 'ThisHost'
    });

    //Overriding the response output and query input to be hidden
    this.output('response', {
        'visibility': 'expert'
    });

    this.input('query', {
        'type': 'string',
        'visibility': 'expert'
    });

};

//Overriding SemanticRepositoryQuery
exports.filterResponse = function(response){
    var data = JSON.parse(response);
    var hostModules = [];
    var accessorModules = [];
    var typeFound = false;

    if(data && data.results && data.results.bindings){
        var dataArray = data.results.bindings;
        
        //If the accessor doesn't have the type "Interface"
        //after inference, it must not appear in any triples and is unknown
        //in the ontology. This is an invalid query.

        //Sort responses by category (accessor module, host module, type of the so called accessor)
        dataArray.map(function(x){
            if(x.host && x.host.value){
                hostModules.push(x.host.value);
            }
            if(x.acc && x.acc.value){
                accessorModules.push(x.acc.value);
            }
            if(x.type && x.type.value === "http://ptolemy.berkeley.edu/accessors#Interface"){
                typeFound = true;
            }
        });

        if(!typeFound){
            error("Specified accessor doesn't exist in the ontology. An accessor with any triples at all should have type 'Interface' (by inference), and this one doesn't.");
        }

        hostModules.sort();
        accessorModules.sort();

        //Compare arrays to see if they match
        var match = true;
        if( accessorModules.length != hostModules.length) match = false;
        for(var i = 0; i < accessorModules.length; i++){
            if(hostModules[i] != accessorModules[i]) {
                match = false;
                break;
            }
        }
        this.send('compatible', match);
    } else{
        //If the query failed entirely send an error and report incompatible
        error("HostCompatability: Query to Semantic Repository failed. Outputing false compatibility.");
        this.send('compatible', false);
    }


    //The hidden response output still needs the raw json data to be returned.
    return data;
};

//Overriding SemanticRepositoryQuery
exports.initialize = function(){
    exports.ssuper.initialize.call(this);
    var thiz = this;

    this.addInputHandler('accessorName', function(){
        var accName = thiz.get('accessorName');
        var accHostName = thiz.getParameter('accessorHostName');
        if(accHostName === 'ThisHost'){
            accHostName = getHostName();
        }
        
        var constructedQuery = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>" +
                                "PREFIX acc: <http://ptolemy.berkeley.edu/accessors#>" +
                                "PREFIX host: <http://ptolemy.berkeley.edu/hosts#>" +
                                "select distinct ?host ?acc ?type where {" +
                                    "{{{host:Host.Common host:Implements ?host} UNION {host:Host." + accHostName + " host:Implements ?host}}" +  
                                    "{<http://ptolemy.berkeley.edu/accessors/" + accName + "> acc:Requires ?host} } UNION " +
                                    "{<http://ptolemy.berkeley.edu/accessors/" + accName + "> acc:Requires ?acc} UNION" +
                                    "{<http://ptolemy.berkeley.edu/accessors/" + accName + "> rdf:type ?type}" + 
                                "}";

        thiz.send('query', constructedQuery);
    });
};