Programming A-Stack with BML

Version 2 of atomiton stack allows for co-existence of v1-style facet script and other legacy technologies along with new v3 technology preview. BML is a part of that showcase.
Important: v3 showcase in v2 is just that, a showcase. This is not a production quality facility and should not be used as such. Since BML is quite a departure from traditional facet script programming in v1, the main intent here is to use this preview facility as an educational tool and to smooth transition from the old set of technologies to the new.

Name convention

All v3 showcase facilities have version number '3' in their names.

SffFacetAgentFacet3

V3 showcase deployment facility runs alongside with standard facet agent. The operations of facet agent facet v3 virtually identical to of v1 and v2. That is, the only difference is that you would make a deployment request to http://host:port/fid-SffFacetAgentFacet3 and place your packages for auto deployment into "sff.auto.deploy3" folder.

Echo facet example

A standard example of HTTP server functionality is echo facet which simply echoes request back:

# Echo facet exampleNewFacetInstance(fid: echo, name: echo, type: SffMessageFacet3): Action(name: OnOpen) => ModifyPipeline: HttpServerExtensionArgs; Action(name: OnRequest): $out = Message(type: cdm): @@Value: $$.stdin.lastGetData(); $sent = $$.stdout.putNextValue($out);

Here we use SffMessageFacet3 type facet. Only two actions are defined in this facet:

  • OnOpen action is invoked on new connection open event. It modifies pipeline for HTTP protocol. This is the same as in v2.
  • OnRequest action is invoked on each request. Here we compose response message in variable $out using TP and send it back.

Communication pipeline is represented by $$.stdin and $$.stdout objects which are defined in system data store so they are readily available for template processing without any copying.

$$.StdIn and $$.StdOut system variables

As the names suggest, $$.stdin and $$.stdout provide standard means of communication over default pipeline. Each variable represents a system object which implements specific API.
$$.stdin provides the following methods:

  • SVar lastGet() – returns fulfilled promise object of the last "get" operation. For a server pipeline this would return the last request object wrapped in a fulfilled promise
  • Object lastGetValue() – returns the actual value of the last "get" operation. For a server pipeline this would be the last request object
  • ML lastGetData() – returns the value of the last "get" operation converted into ML data structure
  • ML lastGetM() – returns the value of the last "get" operation converted into standard message structure
  • Object lastGetMV() – returns last message value. No assumptions are made about value type.
  • ML lastGetMA() – same as lastGetMV(), but also with added URI arguments if any. This is only useful with HTTP protocol where URI parameters can be specified along with the message. Note that message value is assumed to be a structure here.


For each method returning a structure there is also a method which returns compiled structure. That is, there are

  • ML lastGetDataC()
  • ML lastGetMC()
  • ML lastGetMAC()
  • ML lastGetMVC() – will return null if message value is not a structure

These methods are used when received structure needs to be template processed and/or executed as a program. Thus, in the echo example above we do use TP to compose response message, but the actual content is simply copied into the response and therefore does not need to be compiled and therefore lastGetData() method is used.
$$.stdout provides the following methods:

  • putNextValue(Object) – places given argument into standard output stream. For a server pipeline this would send a response

$$.v2 system variable

$$.v2 variable provides access to the legacy v2 engine context which, in turn, implements about 200 methods. The most useful for an application are the following:

  • Object getRequest() – get current request object
  • Object getRequest(Boolean create) – create empty request if currently null and argument is true, otherwise return current request
  • Object setRequest(Object) – set given request object as current, returns previous one
  • Object getResponse() – get current response object
  • Object getResponse(Boolean create) – create empty response if currently null and argument is true, otherwise return current response
  • Object setResponse(Object) set given response object as current, returns previous one
  • String getServerId() – get current server ID
  • String getServerProtocol()
  • Void setServerId(String id)
  • String getClientId()
  • String getClientProtocol()
  • Void setClientId(String id)
  • String getSourceId()
  • Void setSourceId(String id)
  • Object getLocalData(Object key)
  • Object setLocalData(Object key, Object val)
  • Object addLocalData(Object key, Object val)
  • Object delLocalData(Object key)
  • Object delLocalData(Object key, Object val)
  • Object getProcessData(Object key)
  • Object setProcessData(Object key, Object val)
  • ...

Message executor example

In this example we will receive a message from a websocket and execute it as a program:

# Executor facet example
NewFacetInstance(fid: wsexec, name: wsexec, type: SffMessageFacet3): Action(name: OnOpen) => ModifyPipeline: WsServerExtensionArgs; Action(name: OnRequest) => Inline = $$.stdin.lastGetMVC();

Here we configure pipeline for websocket protocol in OnOpen and then simply inline received and compiled message value structure. Note that in this case compilation is required hence we use lastGetMVC() method.

Other facet invocation example

Since different facet types provide different capabilities, in many cases you need to be able to invoke an action in the context of another facet. We can use message executor example above to illustrate how it can be done. You can send the following message:

# Invoke wstest facetscope(fid: wstest): OnRequest; # simply forward the requestscope(fid: wstest): # execute FacetScript DoResponse: log: my log message; Process => Message => Value: my message;
$res = $$.stdout.putNextValue($$.v2.getResponse()); #send response

Here we do two invocations of the standard wstest facet which is usually comes with the engine. The first call scope(fid: wstest): OnRequest; simply invokes the OnRequest action of wstest facet and the second call executes a piece of FacetScript (recall that wstest is a v2 facet and cannot execute BML). Given that OnRequest action of wstest facet does broadcast the message into all connections, you should see this message echoed on all connected websocket clients of wstest facet, then "my log message" appear in the log and finally "my message" as a response on the current pipeline.
Note that in order to execute an action in the context of another facet we've specified our target facet via "fid" parameter: fid: wstest. This provides seamless integration between v2 and v3 facet types.
Also note that with the exception of default legacy broadcast, all communications in BML are explicit. Thus we explicitly send the response composed by wstest facet and stored in v2 context: $res = $$.stdout.putNextValue($$.v2.getResponse());