-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
84 changed files
with
2,658 additions
and
729 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,7 @@ h3 { | |
} | ||
|
||
.note { | ||
background-color: rgba(128,255,128,.4); | ||
background-color: #4ecb96; | ||
} | ||
|
||
.tip { | ||
|
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,102 @@ | ||
Embedding BPjs in an Application | ||
================================ | ||
|
||
.. todo:: Write this. | ||
Overview | ||
-------- | ||
|
||
We'll have: | ||
The BPjs library can be embedded in larger Java programs. The setting is useful in | ||
cases where you want the control logic to be implemented using behavioral programming, | ||
and thus need to translate incoming signals to BP events, and selected BP events to | ||
instructions to, e.g. actuators, databases, or web-services. | ||
|
||
* ref to inclusion in project | ||
The layers of an application running a BPjs ``BProgram`` are described in the figure below. | ||
The BP code (top layer) is the BPjs code, written in Javascript. It can interact with | ||
the BPjs runtime using the :doc:`BPjsTutorial/bp-object`. The host application can make | ||
other Java objects available to the Javascript code, as will be explained later. | ||
|
||
* add listeners | ||
The BPjs layer serves as a runtime environment for the BProgram. The host application has | ||
to instantiate a ``BProgram`` object, and pass it to a ``BProgramRunner``. The host application | ||
can listen to events of the running b-program (such as start, end, b-thread added, and - of course - b-event selected). | ||
Additionally, the host application can provide custom event selection strategy, in case | ||
the default one it not good enough. | ||
|
||
* set daemon mode | ||
|
||
* push an event | ||
.. figure:: images/BPjs-stack.png | ||
:scale: 50% | ||
:alt: Running BPjs application stack | ||
:align: center | ||
|
||
The layers of a running BPjs program. The BP program, written in Javascript, | ||
it the top layer. It interacts with the BPjs runtime using ``bp``, | ||
a Javascript object added to its context. The hosting Java application controls | ||
the BPjs runtime via its API. It can push event to the ``BProgram``'s external | ||
event queue, and register listeners that are invoked when events are selected. | ||
|
||
|
||
.. figure:: images/bprogram-running.png | ||
:alt: Class diagram for running a BProgram | ||
:align: center | ||
|
||
Class diagram describing the strucutre of an embedded b-program. The client code | ||
generates a BProgram and a BProgramRunner. The runner object consults the b-program's | ||
event selection strategy when selecting events for the b-program it runs. A list of | ||
listener objects are informed whenever an event of interest, such as b-thread | ||
addition or b-event selection, occures. | ||
*Some methods and properties have been omitted for brevity.* | ||
|
||
|
||
.. note:: | ||
**Why is ``BProgram`` separated from ``BProgramRunner``?** | ||
|
||
Because a b-program is also | ||
a model that can be *verified* rather than *ran*. The same ``BProgram`` | ||
object can be passed to a verifier object for verification. | ||
|
||
|
||
|
||
Steps for B-Program Embedding | ||
----------------------------- | ||
|
||
Code setup | ||
~~~~~~~~~~ | ||
|
||
Add BPjs to your classpath. | ||
|
||
See :doc:`install-bpjs`. | ||
|
||
Decide which ``BProgram`` subclass you need. | ||
|
||
`BProgram`_ is an abstract class. Its concrete sub-classes differ on how they obtain their source code. `SingleResourceBProgram`_ reads the code from a resource included with the code (typlically, a .js file bundled in the project's .jars). `StringBProgram`_, on the other hand, takes a Java String as source. Of course, ``BProgram`` can be directly extended as needed. | ||
|
||
Write the BPjs code. | ||
|
||
The code will interact with the runtime using the ``bp`` object. Additional Java classes can be made available to it by using Rhino's `import directives`_, or by adding Java objects to the program's scope (see below). | ||
|
||
At Runtime | ||
~~~~~~~~~~ | ||
|
||
* Instantiate the proper ``BProgram`` sub-class, and supply it with the source BPjs code. | ||
* If needed, set a new ``EventSelectionStrategy``. When no strategy is supplied, SimpleEventSelectionStrategy_ will by used. This strategy randomly selects an event from the set of events that are requested and not blocked. | ||
* If needed, add Java objects to the global b-program scope using `putInGlobalScope`_. | ||
* Instantiate a ``BProgramRunner`` object, and supply it with the ``BProgram`` instance. | ||
* Add listeners to the runner. | ||
* In the common case when the program needs to wait for external events (such as GUI interactions), set the ``isDaemon`` property of the ``BProgram`` to ``true``. | ||
* Call ``BProgramRunner::start()``. | ||
|
||
The BProgram will start running. Lifecycle and behavioral events will be passed to the listener objects. In case the host application would like to push an external event to the embedded b-program (e.g. because of a network request, or a user click), it should use the ``BProgram``'s `enqueueExternalEvent`_ method. | ||
|
||
.. tip:: | ||
BPjs' source code contains many examples of embedded BPjs programs - most of the unit tests that involve a b-program. For a more complete example, refer to the `RunFile`_ class, which implements the command-line tool for running BPjs code. | ||
|
||
.. tip:: | ||
SampleBPjsProject_ can serve as a template project for embedding BPjs in a Java application. You can fork it on GitHub and start building your application from there. | ||
|
||
.. _import directives: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/Scripting_Java | ||
.. _BProgram: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.4/il/ac/bgu/cs/bp/bpjs/bprogram/runtimeengine/BProgram.html | ||
.. _SingleResourceBProgram: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.4/il/ac/bgu/cs/bp/bpjs/bprogram/runtimeengine/SingleResourceBProgram.html | ||
.. _StringBProgram: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.4/il/ac/bgu/cs/bp/bpjs/bprogram/runtimeengine/StringBProgram.html | ||
.. _putInGlobalScope: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.4/il/ac/bgu/cs/bp/bpjs/bprogram/runtimeengine/BProgram.html#putInGlobalScope-java.lang.String-java.lang.Object- | ||
.. _enqueueExternalEvent: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.4/il/ac/bgu/cs/bp/bpjs/bprogram/runtimeengine/BProgram.html#enqueueExternalEvent-il.ac.bgu.cs.bp.bpjs.events.BEvent- | ||
.. _RunFile: https://github.com/bThink-BGU/BPjs/blob/develop/src/main/java/il/ac/bgu/cs/bp/bpjs/mains/RunFile.java | ||
.. _SimpleEventSelectionStrategy: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.4/il/ac/bgu/cs/bp/bpjs/eventselection/SimpleEventSelectionStrategy.html | ||
.. _SampleBPjsProject: https://github.com/bThink-BGU/SampleBPjsProject |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
bp.registerBThread("bt-1", function () { | ||
bsync({ request: bp.Event("1") }, 1); | ||
}); | ||
|
||
bp.registerBThread("bt-2", function () { | ||
bsync({ request: bp.Event("2") }, 2); | ||
}); | ||
|
||
// Has no extra data on the bsync call. | ||
bp.registerBThread("bt-3", function () { | ||
bsync( {request: bp.Event("3")} ); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
class PriorityEss implements EventSelectionStrategy { | ||
|
||
@Override | ||
public Set<BEvent> selectableEvents(Set<BSyncStatement> statements, List<BEvent> externalEvents) { | ||
|
||
EventSet blocked = ComposableEventSet.anyOf(statements.stream() | ||
.filter( stmt -> stmt!=null ) | ||
.map(BSyncStatement::getBlock ) | ||
.filter(r -> r != EventSets.none ) | ||
.collect( Collectors.toSet() ) ); | ||
|
||
Iterator<BSyncStatement> stmts = statements.iterator(); | ||
if ( stmts.hasNext() ) { | ||
BSyncStatement firstStmt = stmts.next(); | ||
Set<BEvent> selectable = getNotBlocked(firstStmt, blocked); | ||
int minValue = getValue( firstStmt ); | ||
|
||
while ( stmts.hasNext() ) { | ||
BSyncStatement curStmt = stmts.next(); | ||
int curValue = getValue(curStmt); | ||
if ( curValue < minValue ) { | ||
minValue = curValue; | ||
selectable = getNotBlocked(curStmt, blocked); | ||
} | ||
} | ||
return new HashSet<>(selectable); | ||
} else { | ||
return Collections.emptySet(); | ||
} | ||
} | ||
|
||
@Override | ||
public Optional<EventSelectionResult> select(Set<BSyncStatement> statements, List<BEvent> externalEvents, Set<BEvent> selectableEvents) { | ||
if ( selectableEvents.isEmpty() ) { | ||
return Optional.empty(); | ||
} else { | ||
return Optional.of( new EventSelectionResult(selectableEvents.iterator().next())); | ||
} | ||
} | ||
|
||
private int getValue( BSyncStatement stmt ) { | ||
return stmt.hasData() ? ((Number)stmt.getData()).intValue() : Integer.MAX_VALUE; | ||
} | ||
|
||
private Set<BEvent> getNotBlocked(BSyncStatement stmt, EventSet blocked) { | ||
try { | ||
Context.enter(); | ||
return stmt.getRequest().stream() | ||
.filter( req -> !blocked.contains(req) ) | ||
.collect( toSet() ); | ||
} finally { | ||
Context.exit(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
Alter Event Selection Algorithm | ||
=============================== | ||
|
||
In standard behavioral programming, the b-thread coordinator, or b-program, is allowed to choose any event that is *requested and not blocked*. Even on modestly sized b-programs, this leaves the event selection algorithm with plenty of wiggle room to make its choice. By default, BPjs will randomly select a requested-and-not-blocked event. Algorithms that make more informed choices are, of course, possible. BPjs makes it easy to develop them, and make them reusable. | ||
|
||
|
||
Meet ``EventSelectionStrategy`` | ||
------------------------------- | ||
|
||
Each b-program has an event selection strategy, implementing the `EventSelectionStrategy`_ interface. Given a b-program state at a synchronization point, an ``EventSelectionStrategy`` object can generate a set of selectable events, and then select a single event out of them. Accordingly, the ``EventSelectionStrategy`` interface defines only two methods: ``selectableEvents(...)`` and ``select(...)``. | ||
|
||
The event selection strategy is used during both program execution and verification. During verification, the strategy is used to generate the possible selectable events; during execution, the strategy both generates the selectable eventset and selects a single event. | ||
|
||
Both of ``EventSelectionStrategy``\'s methods accept the program's state at the synchronization point. This state is composed of all the b-sync statements of participating b-threads, and the external event queue. ``selectableEvents`` returns a plain-old Java ``Set``, that can also possibly be empty. During execution, ``select`` recieves the program's state as well as the selectable event set obtained from the call to ``selectableEvents``. It does not return an ``Event``, though -- it returns a richer ``Optional<EventSelectionResult>`` object. | ||
|
||
The `EventSelectionResult`_ object holds a selected event, and a set of indices to events in the external event queue. When receiving an `EventSelectionResult`, the b-program will remove the external events at those indices. This allows an event selection strategy a considerable degree of freedom for dealing with external event sets. For example, it can make the event list act like a set, by passing all the indices of events that are equal to the selected event. | ||
|
||
|
||
Hinted ``bsync``\s | ||
------------------ | ||
|
||
Some event selection strategies may depend on internal b-thread state. For example, a b-thread may define a HOT/COLD modality, as defined by Live Sequence Charts. A b-thread in a "HOT" state must advance, whereas a b-thread in a "COLD" state can forever stay in its current position without violating the system's specification. | ||
|
||
To this end, the ``bsync`` statement in BPjs has an optional second parameter. BPjs makes no assumptions about the type of this parameter - it just stores it in the b-thread's `synchronization statement`_, where is it made available to the event selection strategy through the ``getData()`` method. | ||
|
||
|
||
Sample Strategy: Priority-Based Selection | ||
----------------------------------------- | ||
|
||
Let's look at a sample event selection strategy, based on priority. Under this strategy, the b-threads may add to their ``bsync`` statements a "priority" integer. The strategy finds a b-thread with the lowest priority, and selects an event that it requested, and was not blocked. Here's the code, followed by a short discussion. | ||
|
||
.. literalinclude:: code/ess.java | ||
:linenos: | ||
:language: java | ||
|
||
|
||
The ``selectableEvents`` method begins by creating a set of all blocked events (lines 6-10). It then iterates over the ``BSyncStatement``\s, maintaining the minimal value it found so far. If a lower value is found, it creates a set of the events it requested and were not blocked (lines 15 and 23). Lastly, it returns the last such set found (line 26). | ||
|
||
Since all of the work was done in the ``selectableEvents`` method, the ``select`` method has very little left to do: it selects the first event from the selectable event set passed to it. If that set is empty, it returns the empty ``Optional``. | ||
|
||
There are two other interesting methods in this code. ``getValue`` (lines 41-43) extracts the priority integer from the statement. Note that the strategy also deals with a case where no such integer was provided. | ||
|
||
``getNotBlocked`` (lines 45-54) takes a ``BSyncStatement`` and a blocked ``EventSet``, and returns the non-blocked subset of events requested by the statement. Note that ``EventSet`` is not ``Set<Event>`` -- ``EventSet`` is a predicate, an interface consisting of a single method: ``contains``. Quite often it will include one or more Javascript functions that have to be evaluated. For this reason, ``getNotBlocked`` has to enter and exit a Javascript execution context (lines 47 and 52, respectively). | ||
|
||
The b-program using this event selection strategy is shown below. Note that b-threads "bt-1" and "bt-2" provide a priority integer, while "bt-3" does not. | ||
|
||
.. literalinclude:: code/b-prog.js | ||
:linenos: | ||
:language: javascript | ||
|
||
.. warning:: The above strategy is intended for explenatory purposes, and is probabaly too simplistic for real-world use. It ignores external events, assumes priorities are unique, and if all the events requested by the b-thread with the lowest priority are blocked, it claims there are no selectable events. | ||
|
||
.. tip:: The above strategy and b-program are part of BPjs' `unit tests`_. | ||
|
||
|
||
.. _EventSelectionStrategy: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.5/il/ac/bgu/cs/bp/bpjs/eventselection/EventSelectionStrategy.html | ||
.. _EventSelectionResult: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.5/il/ac/bgu/cs/bp/bpjs/eventselection/EventSelectionResult.html | ||
.. _synchronization statement: http://static.javadoc.io/com.github.bthink-bgu/BPjs/0.8.5/il/ac/bgu/cs/bp/bpjs/bprogram/runtimeengine/BSyncStatement.html | ||
.. _unit tests: https://github.com/bThink-BGU/BPjs/blob/develop/src/test/java/il/ac/bgu/cs/bp/bpjs/examples/StatementsWithDataTest.java |
Oops, something went wrong.