Syntax of JavaFBP (Java Implementation of FBP)

Network Definitions

In my book, "Flow-Based Programming", I describe the syntax of the network specifications of various FBP dialects that were in existence when the book was written. JavaFBP, the Java implementation of the FBP concepts, did not exist at that time, so this web page has been added describing the syntax of JavaFBP network definitions.

In JavaFBP we not only code components in Java but also define the networks as Java programs. Some examples of the latter can be found in the directory com.jpmorrsn.javaFBP.test.networks in the JavaFBP ZIP file on the Flow-Based Programming project on SourceForge. An earlier version of the code was added to the CVS directories in SourceForge, but this is not up-to-date.

One advantage of defining the network as executable code, as compared with other approaches that merely list connections in a language-independent way, is that the network can contain additional logic. This logic then controls the way the network is defined, rather than the way it runs. Some may regard this as a defect, rather than as an asset, and both views can certainly be defended, but one of the neat things it enables us to do is to adjust multiplexing levels of various structures in the diagram using a table of values (remember the multiplexing example in Sample DrawFlow Diagram). One merely retrieves a value from a table for the degree of multiplexing in a particular structure in the diagram, and this value is then used both as the index of a loop invoking the connect statement, and as the index for the elements of an array-type port (see below for both of these terms).

Since the way the syntax relates to the underlying diagram may not be all that clear, a brief description is in order.  At the end of this page, I have given an extremely simple JavaFBP component.

Any JavaFBP network definition starts as follows:

public class xxxxxx extends Network {

protected void define() throws Throwable {


where xxxxxx is the Network name, including the usual imports, copyright statements, etc. Of course you will have to import classes for JavaFBP objects, such as Network and Component, as well as any JavaFBP "verb" classes you may be using.

The network definition is terminated with:

}
public static void main(String[] argv) {
new xxxxxx().go();
}
}

In between the beginning and the ending statements defining the network, you specify a list of connections, using the following methods, which I will refer to as "clauses":

Every component instance must have a unique character string identifying it, which allows other component instances or initial information packets (IIPs) to be attached to it via a connection.

The following method call: 

component("xxxx")

returns a reference to a component instance. The first reference to this particular component instance must specify the component class to be executed by that occurrence. This is done by coding

component("xxxx", cccc.class)

where cccc  is the name of the Java module to be executed.

Similarly, a port is identified by a port clause, e.g. port("xxxx").

A port may be an array-type port, in which case the port clauses referring to its elements have index values, as follows: 

port("xxxx",n)

where "n" runs up monotonically from 0. Each element of the port array will be connected to a different component occurrence or IIP.

A connect or initialize clause may contain one or more component clauses and their corresponding port clauses embedded within it, as e.g.

     connect(component("Read", ReadText.class),
         port("OUT"),
         component("Splitter1", Splitter1.class),
         port("IN"));

or the connect and component portions may be in separate statements, provided component precedes any connects that reference it.

A connect contains:

Optionally a connect may have a fifth parameter: the connection capacity, specified as an int.  If this is omitted, the default value is used: 1 for testing, or 10 for production (this currently has to be changed by hand in the Network.class).  If an asterisk String ("*") is specified for the "from" port, this indicates a signal generated when the "from" component instance terminates; if it is specified for the "to" port, this indicates a delay - the "to" component instance does not start until a signal is received at this port.

An initialize clause contains:

as e.g.

     initialize(new FileReader("c:\\com\\jpmorrsn\\eb2engine\\test\\data\\myXML3.txt"),
       component("Read"),
           port("SOURCE"));

One last point: any number of "from" ports can be connected to a single "to" port; only one "to" port can ever be connected to a given "from" port.

Sample Network

Let us code up a network implementing the following picture:

update.jpg

First list the component clauses, together with the component classes they are to execute (assuming that component classes have been written to execute the various nodes of the diagram), e.g.:

 
component("Read Masters",Read.class)
component("Read Details",Read.class)
component("Collate",Collate.class)
component("Process Merged Stream",Proc.class)
component("Write New Masters",Write.class)
component("Summary & Errors",Report.class)

Now these component clauses may either be made into separate statements or they can be imbedded into the connect statements that follow.  Here are the connections in the diagram, without imbedded component clauses:

  connect(component("Read Masters"),port("OUT"),component("Collate"),
port("IN",0));    // array port
connect(component("Read Details"),port("OUT"),component("Collate"),
port("IN",1));      // array port
connect(component("Collate"),port("OUT"),component("Process Merged Stream"),
port("IN"));
connect(component("Process Merged Stream"),port("OUTM"),
component("Write New Masters"),port("IN"));
connect(component("Process Merged Stream"),port("OUTSE"),
component("Summary & Errors"),port("IN"));

Each item in this list is a separate Java statement.

We can now add the class designation to the first component clause referencing a particular component occurrence, giving the following:

  
connect(component("Read Masters",Read.class),port("OUT"),
    component("Collate",Collate.class), port("IN",0)); // array port
  connect(component("Read Details",Read.class),port("OUT"),
     component("Collate"),port("IN",1)); // array port
  connect(component("Collate"),port("OUT"),
component("Process Merged Stream",Proc.class),port("IN"));
connect(component("Process Merged Stream"),port("OUTM"),
component("Write New Masters",Write.class),port("IN"));
connect(component("Process Merged Stream"),port("OUTSE"),
component("Summary & Errors",Report.class),port("IN"));

Now "Read Masters" and "Read Details" use the same Java class, so we need some way to indicate the name of the file that each is going to read. This is done using Initial Information Packets (IIPs). In this case they might usefully specify FileReader objects, so we need to add two initialize clauses, as follows:

  
initialize(new FileReader("c:\\mastfile"),
component("Read Masters"),
port("SOURCE"));
initialize(new FileReader("c:\\detlfile"),
component("Read Details"),
port("SOURCE"));

Note that, since both "Read" component occurrences use the same class code, they naturally have the same port names - of course, the ports are attached to different IIPs.

Remember that back-slashes have to be doubled in Java character strings!

"Write New Masters" will have to have an IIP to specify the output destination - perhaps:

  
initialize(new FileWriter("c:\\newmast"),
component("Write New Masters"),
port("DESTINATION"));

Note also that this IIP is not a destination for the Writer - it is an object used by this component occurrence so that the latter can figure out where to send data to.

Add the beginning and ending statements, and you're done!   The actual sequence of connect and initialize statements is irrelevant.

Here is the final result:

  public class xxxxxx extends Network {

protected void define() throws Throwable {
connect(component("Read Masters",Read.class),port("OUT"),
component("Collate",Collate.class),port("IN",0)); // array port
connect(component("Read Details",Read.class),port("OUT"),
component("Collate"),port("IN",1));// array port
connect(component("Collate"),port("OUT"),
component("Process Merged Stream",Proc.class),port("IN"));
connect(component("Process Merged Stream"),port("OUTM"),
component("Write New Masters",Write.class),port("IN"));
connect(component("Process Merged Stream"),port("OUTSE"),
component("Summary & Errors",Report.class),port("IN"));
initialize(new FileReader("c:\\mastfile"),
component("Read Masters"),
port("SOURCE"));
initialize(new FileReader("c:\\detlfile"),
component("Read Details"),
port("SOURCE"));
initialize(new FileWriter("c:\\newmast"),
component("Write New Masters"),
port("DESTINATION"));

}

public static void main(String[] argv) {
new xxxxxx().go();
}
}




Alternative (Simplified) Notation (JavaFBP-2.0)

In the latest release of JavaFBP, we have introduced a new, simplified notation, in addition to that shown above.  In this notation connect specifies two character strings, and initialize specifies an object and a character string.   The combination of component and port are specified together as a single character string, with the two parts joined with a period.  Array port indices, if required, are specified using square brackets, e.g.

"component.port[3]"

The old port notation will still be supported, but is only really needed when the port index is a variable.  When debugging, it will be noted that the square bracket notation is used in trace lines, even when it was not used in the network definition.

Component names must of course not include periods or most special characters, but they may include blanks, numerals, hyphens and underscores, and they must be associated with their implementing class using a (preceding) component statement.

Here is the above network using the new notation:

 public class xxxxxx extends Network {

protected void define() throws Throwable {
component("Read Masters",Read.class);
component("Read Details",Read.class);
component("Collate",Collate.class);
component("Process Merged Stream",Proc.class);
component("Write New Masters",Write.class);
component("Summary & Errors",Report.class);
connect("Read Masters.OUT", "Collate.IN[0]");
connect("Read Details.OUT", "Collate.IN[1]");
connect("Collate.OUT"), "Process Merged Stream.IN");
connect("Process Merged Stream.OUTM", "Write New Masters.IN");
connect("Process Merged Stream.OUTSE", "Summary & Errors.IN");
initialize(new FileReader("c:\\mastfile"), "Read Masters.SOURCE");
initialize(new FileReader("c:\\detlfile"), "Read Details.SOURCE");
initialize(new FileWriter("c:\\newmast"), "Write New Masters.DESTINATION");
}

public static void main(String[] argv) {
new xxxxxx().go();
}
}

Sample JavaFBP Component

This component generates a stream of 'n' IPs, where 'n' is specified in an InitializationConnection (specified by an initialize clause in the foregoing). Each IP just contains an arbitrary string of characters, in order to illustrate the concept.  Of course any copyright information included is up to the developer.

package com.jpmorrsn.javaFBP.verbs;

import com.jpmorrsn.javaFBP.*;


/** Component to generate a stream of 'n' packets, where 'n' is
* specified in an InitializationConnection.
*/

public class Generate extends Component {

static final String copyright = "Copyright .....";


OutputPort outport;

InputPort count;


protected void execute() throws Throwable {
Packet ctp = count.receive();
if (ctp == null) {
return;
}
Integer cti = (Integer) ctp.getContent();
int ct = cti.intValue();
drop(ctp); // drop statement changed
count.close(); // added as per note below
String s = "12345abc";
for (int i = 0; i < ct; i++) {
Packet p = create(s);
outport.send(p); // send now returns void
}

}
protected Object[] introspect() {
return new Object[] {
"generates a set of Packets under control of a counter" ,
"OUT", "output", String.class,
"lines read",
"COUNT", "parameter", Integer.class,
"Count of number of entities to be generated"};
}
protected void openPorts() {

outport = openOutput("OUT");
outport.setType(String.class);

count = openInput("COUNT");
count.setType(Integer.class);

}
}

The scheduling rules for most FBP implementations are described in the chapter of my book called Scheduling Rules.

The previous Java implementation of FBP (javaFBP-1.5.3) presents an IIP to a component once per activation. This has been changed in the latest implementation (JavaFBP-2.0) to once per invocation.  In practice this will only affect "non-loopers" (components that get reactivated multiple times).  

There are a few minor changes to component code for JavaFBP-2.0: