Quantcast
Channel: Intel Developer Zone Articles
Viewing all articles
Browse latest Browse all 3384

Thought Processes Programming Guide

$
0
0

Parameters
     Pre-Defined Parameters
     Pre-Defined Objects
     Concise Syntax
     params Function
     Implicit Space Parameter
     Multiple Values for Parameters

JavaScript Environment

Debug
     Debugging THOPs
     What's my Query Again?
     Use Debug to Troubleshoot THOPs

Testing
     Test a THOP from the Command Line

Tips
     Dos and Don'ts
     THOP Editor Hidden Gems
     Unsupported REST Calls
     Using .get() on Connection and Other Query Objects

Asynchronous THOPs (2.0)
     Calling THOPs from THOPs
     Writing Non-Blocking THOP Code
     Why Async I/0?

JavaScript Help
 

Parameters

The run function of a Thought Process (THOP) takes a single parameter, which is a multi-map of key/value pairs that were specified when running the THOPs 1.0.

function run(p) {...}

Given the following REST call to a THOP:

/proc/find_connections/result?name=Saffron&category=company&category=location

The parameter p will look like this:

   { name: "Saffron", category: [ "company", "location" ] }

'p' is never null, but it might not have a property.

Pre-defined Parameters

The following are reserved parameter names when calling THOPs:

space
When set, you can omit the space name when using queries. That is, instead of writing connections(p.space), you can just use connections().

access_key
The key used to run this THOP.
 
signature
The signature of the call (this is not useful per se; make sure your THOP does not rely on a parameter called signature.

thop.result=raw
Returns the result of a THOP directly, without wrapping it inside a { result: "..." } object.

Pre-defined Objects

local
THOPs 1.0 only.
This is an instance of SaffronMemoryBase pointing to the local SaffronMemoryBase system.

local.connections(…) -> connections(…)

query methods in REST API (using local)
THOPs 1.0 only. 
Analogies, attributes, classifications, connections, episodes, information, networks, trends, resources.
 
debug
 
quote
This takes a string and returns a quoted string.

All queries also have a .params(..) function that can be used to define query parameters as a JavaScript object:

connections(‘uksecurity’).params({ q: ‘city:london’, c: ‘country’ }).get();

Concise Syntax

For example, var p = params.p ? params.p : 1; can be written more concisely as follows:

var p = params.p || 1

params Function

You can specify all parameters for a query using the params({...}) function. Note that params({...}) overwrites any parameters set, so use with care.

Compare the following 2 lines of code:

connections(space).q('john').c('person').get()
connections(space).params({ q: 'john', c: 'person' }).get();

Implicit Space Parameter

You can write THOP code that works for any space by using the implicit space parameter.

Example:

return connections().q('person').get();

Note that no space was specified in the connections function. In that case, callers of the THOP are expected to pass the space name in the reserved parameter 'space'.

Multiple Values for Parameters

If a query parameter can be specified multiple times (like c() in a connection query()), you have a few options to specify them:

connections().c('cat1').c('cat2').c('cat3');

Or like this:

connections().c('cat1','cat2','cat3');

If you have the data in an array already, you can use the apply function.

var cats = ['cat1', 'cat2', 'cat3'];
var query = connections();
query.c.apply(query, cats); 

If you use the param function, you can use an array as well:

connections().params({ c: ['cat1', 'cat2', 'cat3']});

Multiple identical parameters is also supported.

When using the REST API to call a THOP:

c=city&c=country&c=person

it is translated into an array of values. The params argument looks like this:

{ c: [ 'city', 'country', 'person' ] }

JavaScript Environment

THOPs are written in JavaScript code.

The run-time environment is very different to the one available in browsers. There is no window object, for example. In order to make working with JavaScript easy, the following libraries are loaded and made available in the context in which a THOP runs:

Lo-Dash (http://lodash.com/)
Contains dozens of useful functions to manipulate arrays, objects, and collections. If a result returned from a Saffron Query API call has a result array by the name of r, it is automatically wrapped using the _(...) function. This makes all lo-dash functions available on r itself.
 
JSON.js
Adds the standard JSON.stringify and JSON.parse functions. Return values from Saffron Query API calls are automatically parsed using JSON.parse.
 
resty
A simple JSON-centered HTTP-client which can be used with any Saffron REST service. It has a single function getJSON(url, accessKey, secretCode) and returns the content of the URL as string.
 
EcmaScript 5 Shims (https://github.com/es-shims/es5-shim)
THOPs 1.0 Only.

THOPs 1.0 JS code is evaluated in a Rhino container, enhanced with EcmaScript 5 extensions. THOPs 2.0 does not require this because it runs on an ES5 JavaScript engine.

The Rhino environment also allows access to any Java class. This gives a THOP almost complete access to the web service layer in Saffron. Please use this capability wisely.

All global functions and classes are available in the API documentation (http://yourserver:8080/ws/doc)

Debug

Debugging THOPs

THOPBuilder does not include a proper debugger that can step through each line in a THOP. Below are the current available actions.

debug(...) can be used to add debug information that is returned as part of the result object.

Example:

function run(p) {
 debug(p);
 return [{hello: p.name || 'world!'}];
}

When run like this:

curl http://admin:saffron@localhost:8080/ws/rest/proc/helloworld/result?name=Scaramanga

The resulting JSON will look like this:

{"result":"[{\"hello\":\"Scaramanga\"}]","duration":1,"error":null,"debug":"{\"name\":\"Scaramanga\"}"}

Note the debug section!

If you use THOPBuilder in Intellij, run the THOP as Debug to see the Debug output:

-- Running helloworld
-- Debug output:
{"name":"Scaramanga","access_key":"demo"}
-- Result: helloworld/name=Scaramanga
[
 {"hello": "Scaramanga"
 }
] 

Tip

If you add parameter log=http when calling a THOP, the URL called as well as the result will be added to the debug output (make sure you run your THOP using the Debug action in Intellij).

What's My Query Again?

If you are unsure what your current query looks like (before running .get() or .getRaw()), you can use .uri() to look at the actual URL generated. You can use that with debug() to add debug output that will be returned to you in the 'debug' property of the result object.

Here's an example:

function run(p) {
 debug(connections('jirahadoop').q('test').c('issue').uri());
 return {};
}

returns this:

{"result":"{}","duration":3,"error":null,"debug":"http://localhost:8080/ws/spaces/jirahadoop/connections?q=test&c=issue&"}

Use Debug to Troubleshoot THOPS

Since there is no ordinary debugger available for troubleshooting Thought Processes, you can use the debug(...) method to add debug output alongside the result of your THOP. Debug(...) will automatically convert any object given to JSON. As seen in the first example, the debug output is delivered alongside the result.

If an error occurs when calling a Saffron API, the error message might contain a URL. Open the URL to learn about any errors that occurred when making the call.

Testing

Test a THOP From the Command Line

Below is the simplest way to test a THOP from the command line. An access key is still needed for the moment, but no encoding of the URL is necessary.

curl'http://admin:saffron@localhost:8080/ws/rest/proc/test/result?access_key=demo'

Tips

Dos and Don'ts

Do

  • Use debug(...) to help with troubleshooting.
  • debug(yourQuery.uri()) will show you the URL used. Use the test harness to run
  • Guard against invalid parameters. Anyone with a THOP account

Do not

  • Use global variables

    The behavior of global variables is undefined. In the current THOPs 1.0 implementation, each THOP has its own instance of the Rhino JavaScript Engine. So, invoking the same THOP in parallel runs in that single engine. If your THOP has global variables, changes to the variables will be visible to all invocations.

  • Be careful when using Java classes, such as Packages.java.lang.System.exit(0);

THOPs Editor Hidden Gems

The editor that is used for THOPs contains some hidden gems:

Alt-F
Search for keywords (with regexp etc).
2xAlt-F
Search and replace.

Unsupported REST Calls

You can use the THOPs API to make any kind of call to the SaffronMemoryBase REST API if it starts with the ws/spaces/<spacename> prefix by using the space(name, 'path') function.

Example:

function run(p) {
 var resource = space('uksecurity','resources').params({rr: 'resourceref' }).get();
}

Using .get() on Connection and Other Query Objects

Please keep in mind that calling .get() will always make a call to SaffronMemoryBase. This means:

  1. Hold on to the result of a .get() operation if you want to make calls to it repeatedly.
  2. You can re-use connection objects.

Asynchronous THOPs (2.0)

Calling THOPs from THOPs

You can call other THOPs from a THOP by using the thop.runAsync variable. You can call other THOPs asynchronously and collect the results. 

Example:

function runAsync(p, cb) {
 Promise.all([
 thop.runAsync('test-thop', {name:'Darth Vader'}),
 thop.runAsync('test-thop', {name:'Luke Skywalker'}),
 thop.runAsync('test-thop', {name:'Walter White'})
 ]).then(function(results) {
 debug(results);
 cb(results);
 });
}

The THOP test-thop can be a synchronous or asynchronous THOP. 

In this example, it is simply:

function run(p) {
 console.log("Console output from within THOP");
 debug('name:' + p.name);
 return "Hello " + (p.name || 'world!');
}

Here is the output when run from THOP builder: 

-- Running test-subcall
-- Debug output:
Output from running test-thop
name:Walter White
Output from running test-thop
name:Darth Vader
Output from running test-thop
name:Luke Skywalker
["Hello Darth Vader","Hello Luke Skywalker","Hello Walter White"]
-- Result: test-subcall/
["Hello Darth Vader","Hello Luke Skywalker","Hello Walter White”
]

Writing Non-Blocking THOP Code

Here is a simple example of a THOP that uses async I/O versus the current blocking I/O: 

function runAsync(p, result) {
 analogies('uksecurity').q('city:london').a('city:london').rtr(true).async()
 .then(function (data) { result(data) });
}

Three things are different here:

  • The main function needs to be called runAsync.
  • The second parameter of that function is a callback function that the THOP needs to call with the final result.
  • get() and getRaw() will return right away with a Promise object.

Important: get() will not give you the result of your query, but will return immediately with a promise that the actual result will be delivered (or fail) in the future.

A Promise object has two interesting functions then(...) and catch(...). Any function you pass to then will be called with the result of the REST call.

In the example above, the result of analogies call is then returned as a result of the THOP.

Why Async I/O?

Here is an example that shows how we can make better use of SaffronMemoryBase resources and do things in parallel without actually having to resort to multi-threaded programming.

Keep in mind that THOPs run single-threaded, much like JavaScript runs in the browser.

We can still run things concurrently as shown in this example:

function runAsync(p, result) {
 var p1 = connections('uksecurity').q('london’).async();
 var p2 = connections('uksecurity').q('moscow’).async();
 Promise.all([p1,p2]).then(function (results) {
 results[0].r.push(results[1].r);
 result(results[0].r.value());
 }).catch(function (error){ console.log("Oh my"); console.log(error.message); });
}

This example runs two connection queries, combines the results and returns it, but each connection query is run asynchronously. The requests are being run in parallel as the underlying engine will make two HTTP requests as fast as it can, then wait for I/O.

When the requests are complete, the promise objects p1 and p2 become fulfilled in unspecified order and at an unspecified time.

Using Promise.all, we register a function that is being called when both promises have become fulfilled, returning their results in results in the same order that we used in the Promise.all call.

This way we can run any number of queries in parallel and wait for their 'fulfillment' before doing the next step in our processing. 

JavaScript Help

https://developer.mozilla.org/en-US/docs/Web/JavaScript

http://www.codecademy.com/en/tracks/javascript


Viewing all articles
Browse latest Browse all 3384

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>