├── .classpath
├── .gradle
├── 6.5.1
│ ├── executionHistory
│ │ ├── executionHistory.bin
│ │ └── executionHistory.lock
│ ├── fileChanges
│ │ └── last-build.bin
│ ├── fileHashes
│ │ └── fileHashes.lock
│ └── gc.properties
├── buildOutputCleanup
│ ├── buildOutputCleanup.lock
│ └── cache.properties
├── checksums
│ └── checksums.lock
└── vcs-1
│ └── gc.properties
├── .project
├── Background.md
├── Footer.txt
├── Need_more_detail.jpg
├── README.md
├── Step00
└── README.md
├── Step01
├── README.md
├── Step01.png
└── diagrams
│ └── Step01.drw
├── Step02
├── README.md
└── Step02.png
├── Step03
├── README.md
├── StartsWith.png
├── Step03.png
└── compListPart.png
├── Step04
├── README.md
└── Step04.png
├── Step05
├── README.md
└── Step05.png
├── Step06
├── README.md
├── Step06_code.png
└── code
│ └── Step06.java
├── Step07
└── README.md
├── Step08
├── README.md
└── code
│ └── StartsWith.java
├── Step09
└── README.md
├── Step10
├── README.md
├── Step10.png
└── counter.png
├── Step11
├── README.md
├── Step11-2.png
└── Step11.png
├── Step12
├── README.md
├── Step12-1.png
├── Step12-2.png
├── Step12-3.png
├── Step12-4.png
├── Step12.png
└── code
│ └── Filter.java
├── Step13
└── README.md
├── Step14
├── ClientServer.png
├── README.md
├── Step14-1.png
├── Step14-2.png
├── Step14-3.png
└── Step14-4.png
├── bottling_factory.png
├── renovate.json
└── style.css
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.gradle/6.5.1/executionHistory/executionHistory.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/.gradle/6.5.1/executionHistory/executionHistory.bin
--------------------------------------------------------------------------------
/.gradle/6.5.1/executionHistory/executionHistory.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/.gradle/6.5.1/executionHistory/executionHistory.lock
--------------------------------------------------------------------------------
/.gradle/6.5.1/fileChanges/last-build.bin:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gradle/6.5.1/fileHashes/fileHashes.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/.gradle/6.5.1/fileHashes/fileHashes.lock
--------------------------------------------------------------------------------
/.gradle/6.5.1/gc.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/.gradle/6.5.1/gc.properties
--------------------------------------------------------------------------------
/.gradle/buildOutputCleanup/buildOutputCleanup.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/.gradle/buildOutputCleanup/buildOutputCleanup.lock
--------------------------------------------------------------------------------
/.gradle/buildOutputCleanup/cache.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 13 14:45:04 EDT 2020
2 | gradle.version=6.5.1
3 |
--------------------------------------------------------------------------------
/.gradle/checksums/checksums.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/.gradle/checksums/checksums.lock
--------------------------------------------------------------------------------
/.gradle/vcs-1/gc.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/.gradle/vcs-1/gc.properties
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | FBP Tutorial Filter File
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Background.md:
--------------------------------------------------------------------------------
1 | ## Background
2 |
3 | In the real world, "everything flows". Heraclitus (Ancient Greece, ca.535 – ca.475 BC, known as "the weeping philosopher"), said it first: πάντα ῥεῖ ("panta rhei"). It is reasonable that data should flow too - it flows to and from storage devices, to and from screens, from keyboards, to printers, and sometimes it loops around and gets fed in again! However, this concept doesn't really fit very well with what we call "procedural programming", which feels very different. In fact humans are not particularly good at procedural thinking! Dr. Lance Miller of IBM looked for instances of procedural thinking in real life, and all he could come up with were recipes, and assembling toy kits... Even recipes often have implicit parallelism which we donʼt notice. For instance, “add boiling water” implies that the water must have started boiling while some other step was going on, so that it would be available when needed.
4 |
5 | How do you square this circle? Years of training? Even that may not help a lot! I once had the dubious pleasure of having to modify an update program (not Flow-Based Programming, obviously!) whose author had written the client an explanation of why his enhancement request could not be satisfied, which started, “Owing to the limitations of data processing,...”! My clear recollection is that modifying that program (and, for a conventional program, it was really quite well-written) was only *almost* impossible!
6 |
7 | If application development is mostly about processing *data*, why not use an approach that is data-, rather than procedure-, oriented? Describe the data, and the transforms that have to be applied to it. Maybe start off with the final output data, and then work backwards to the original inputs...?
8 |
9 | We referred above to the "conveyor belt" image. Here is a graphic of a part of such a system for bottling soft-drink cans, taken from a PowerPoint slide deck, showing some of the (perhaps less obvious) advantages of this approach:
10 |
11 | 
12 |
13 | FBP builds on this metaphor! In some ways, this is not a new approach: in the first two thirds of the 20th century (Wikipedia) data processing was largely done using a technology called ["Unit Record"](https://en.wikipedia.org/wiki/Unit_record_equipment) - chunks of data (cards) being transported (hand-carried by humans) between parametrizable components (machines using plug-boards) - all totally asynchronous. Worked pretty well, actually. I once debugged an accounting machine plug-board over the phone, from home, soaking wet (in the early '60s)!
14 |
15 | This tutorial is designed not only to introduce you, the reader, to the *concepts* of Flow-Based Programming (FBP), but to give you a feeling for what it feels like to actually use the tool which supports these concepts in a number of different ways. FBP is "language-agnostic", but in this case we will using Java, as it is more closely integrated with the tool we will be using - [DrawFBP](https://github.com/jpaulm/drawfbp). However, we could equally well use any other language which has an FBP implementation, although it would involve a bit more jumping back and forth between different tools.
16 |
17 | Remember the (good?) old days?! Lovely cartoon from the '70s or '80s:
18 |
19 | 
20 |
--------------------------------------------------------------------------------
/Footer.txt:
--------------------------------------------------------------------------------
1 | Next: [Step6. Generating a running program.](../Step6/Step6.md)
2 |
3 | Index: [Go to higher level.](../README.md)
4 |
--------------------------------------------------------------------------------
/Need_more_detail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Need_more_detail.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Tutorial on Flow-Based Programming (Filter File application)
2 | ===
3 |
4 | ### Filter File with [DrawFBP](https://github.com/jpaulm/drawfbp): use a network of flow-based components to display selected records from files.
5 |
6 | General web site on Flow-Based Programming: https://jpaulm.github.io/fbp/ .
7 |
8 | This tutorial is repeatable, so that concepts can be shared with others, or reinforced and clarified in future, perhaps on a different platform. FBP, as demonstrated here, is fully asynchronous, and uses a "conveyor belt" analogy, rather than being procedural like a number of other systems which also use the term "Flow-Based Programming".
9 |
10 | Using DrawFBP, we design and build a network of components from the [JavaFBP](https://github.com/jpaulm/javafbp) library (jar file), then compile and run in a Windows or Unix environment.
11 |
12 |
13 | ### [Background](Background.md)
14 |
15 | ## Tutorial Steps
16 |
17 | [Step00 - Setup DrawFBP](Step00/)
18 |
19 | [Step01 - Draw an end-to-end diagram.](Step01/)
20 |
21 | [Step02 - Add other parts to the diagram.](Step02/)
22 |
23 | [Step03 - Choose a component for a part.](Step03/)
24 |
25 | [Step04 - Set a value for a part.](Step04/)
26 |
27 | [Step05 - Choose components and set values for other parts.](Step05/)
28 |
29 | [Step06 - Generate a Java program.](Step06/)
30 |
31 | [Step07 - Run the program.](Step07/)
32 |
33 | [Step08 - Inside a component.](Step08/)
34 |
35 | [Step09 - More ideas about design.](Step09/)
36 |
37 | [Step10 - Extend the diagram.](Step10/)
38 |
39 | [Step11 - Combine data flows.](Step11/)
40 |
41 | [Step12 - Subnets.](Step12/)
42 |
43 | [Step13 - "Brackets" and "substreams".](Step12/)
44 |
45 |
46 | **Repeat, with or without an audience!**
47 |
48 |
--------------------------------------------------------------------------------
/Step00/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step00 - Setup DrawFBP
5 |
6 | ### DrawFBP essentials
7 |
8 | Essential parts: DrawFBP diagram tool for FBP networks, including help file; JavaFBP library of FBP components.
9 |
10 | We will start by installing DrawFBP, the FBP diagramming tool. Go to https://github.com/jpaulm/drawfbp/releases , download the latest (non-pre-Release) DrawFBP jar file, and store it on your chosen location for DrawFBP (either your desktop, or another location specifically for your DrawFBP work).
11 |
12 | *Our working assumption is that most users will have access to Windows, and that unix users will be able to adapt these steps to their preferences.*
13 |
14 | Alternatively, you can do a search for `DrawFBP` on Maven. *This will become the preferred location for DrawFBP and its Help facility, and the Java FBP Jar file, once this tutorial is commissioned after our current regression testing.*
15 |
16 | Make sure you have Java installed, by issuing
17 |
18 | java -version
19 |
20 | from the command line. You will also need to define JAVA_HOME to include jre (Java Runtime Environment) and jdk (Java Development Kit) components, using the `set` command, such as:
21 |
22 | C:\Users\bob\drawfbp>set JAVA_HOME=C:\PROGRA~1\Java\jre1.8.0_191\lib;C:\PROGRA~1\Java\jdk1.8.0_191
23 |
24 | ### Starting DrawFBP
25 |
26 | Just double click on the jar file. Alternatively, you can enter the command
27 |
28 | java -jar drawfbp-x.y.z.jar
29 |
30 | from the command line (current version 23 March 2020 is drawfbp-2.19.5.jar).
31 |
32 | When you first fire up DrawFBP, you will see the DrawFBP logo, with 3 connected blocks of different colours. This will last for a few seconds... or until you move the mouse. In normal use, DrawFBP displays the diagram you were working on, so you will not see the logo.
33 |
34 | As you develop various functions in DrawFBP, useful information will be stored in `C:Users\\DrawFBPProperties.xml`.
35 |
36 | If at some later stage of testing, you want to point at a diagram's `.drw` file and run DrawFBP, go to your DrawFBP local directory, and type
37 |
38 | drawfbp.bat
39 |
40 | `drawfbp.bat` references the current DrawFBP jar file, but you can create your own version if you prefer.
41 |
42 | ### Help Facility - DrawFBP Help jar file is now bundled with drawfbp jar file
43 |
44 | ### Locating JavaFBP jar file and preparing Java FBP classes for use
45 |
46 | At this point, you should locate the JavaFBP jar file (it can be found on [Maven](https://search.maven.org/search?q=g:%22com.jpaulmorrison%22%20AND%20a:%22javafbp%22) or in [JavaFBP Releases](https://github.com/jpaulm/javafbp/releases)), download it, and tell DrawFBP where it is, by using the DrawFBP function `File/Locate JavaFBP Jar File`. Once you tell DrawFBP where it is, DrawFBP will remember the location from then on.
47 |
48 | The .class files you are likely to use are available under sub-directories such as `com/jpaulmorrison/fbp/core/components/` and `com/jpaulmorrison/fbp/resourcekit/examples` and so on.
49 |
50 | Index / Next ==>
51 |
52 |
--------------------------------------------------------------------------------
/Step01/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step01 - Draw an end-to-end diagram.
5 |
6 | Here is a possible diagram, showing a simple application which displays the contents of a file:
7 |
8 | 
9 |
10 | To execute this step of the tutorial, you will need to install DrawFBP, and draw this diagram.
11 |
12 | Drawing rules:
13 |
14 | - block descriptions must be unique in a diagram (however, DrawFBP will make them unique if needed)
15 | - port names need only be unique for a given block
16 | - component names may be shared by multiple blocks
17 |
18 | Save the result in a work directory of your choice. If you open it using Wordpad, it should look like the file you get when you click on [this link](diagrams/Step01.drw).
19 |
20 | Of course, if you have trouble drawing the diagram, you can go the other way - simply copy the `.drw` file, and open this file under DrawFBP.
21 |
22 | At this point, you should take a look at the functions provided by DrawFBP. DrawFBP has a Help facility, which takes you through a lot of the DrawFBP functionality.
23 |
24 | Now at this point, you can simply assign real live components to the blocks in the diagrams (plus IIPs and port names), and you will basically have a running program. However, I am going to assume that you want to add a filter function between the two processes in the design phase (rather than later as the application "evolves"), so that is what we will do in Step2.
25 |
26 | <== Previous / Index / Next ==>
27 |
--------------------------------------------------------------------------------
/Step01/Step01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step01/Step01.png
--------------------------------------------------------------------------------
/Step01/diagrams/Step01.drw:
--------------------------------------------------------------------------------
1 |
2 | High Level DiagramFBPtrue
4 | 267 161 29 B9264read
5 | sample
6 | filefalsefalsefalse
7 |
8 | 670 161 30 B9264display
9 | accepted
10 | linesfalsefalsefalse
11 |
12 |
13 | 313161624161293025false0
14 |
--------------------------------------------------------------------------------
/Step02/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step02 - Add other parts to the diagram
5 |
6 | In this step we are going to add a filter function between the two blocks shown above. Filter functions (filters, for short) are commonly used in FBP, and conventionally have two outputs: *accepted* IPs, and *rejected* IPs. Filters should not just drop rejected items, although they can be written this way - it is better for them to route rejected items to another process... which could very well just be a Discard process, if so desired. In this case, we will do exactly that, as shown here.
7 |
8 | 
9 |
10 | The captions `accepted` and `rejected` are generated using a block type in DrawFBP called "Legend".
11 |
12 | When you are ready to add the filter function, you will of course need to delete the existing arrow - right click on the arrow itself, and select Delete.
13 |
14 | <== Previous / Index / Next ==>
--------------------------------------------------------------------------------
/Step02/Step02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step02/Step02.png
--------------------------------------------------------------------------------
/Step03/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Step03 - Choose a component for a part
4 |
5 | For the filter function, we need a component that will match the first character against a character provided as a parameter. As it happens(!), JavaFBP provides a precoded, reusable FBP component called `StartsWith`, which takes a character string as its parameter (specified using an IIP), and whose output port names are ACC and REJ. **FBP is not designed to be a coding language**. The ideal is to work with a library of precoded, pretested components. **You only need to write a component if you can't find an appropriate one - and in that case, you should try to write one that other people will find useful.**
6 |
7 | How do we find a suitable component? Well, the first step is to install JavaFBP ( https://github.com/jpaulm/javafbp ) as described in Step00, and use DrawFBP's `Locate JavaFBP Jar File` function.
8 |
9 | We now have to associate the `StartsWith` component with the filter block. Since the component is in JavaFBP, you will need to use the `Choose Component/Subnet Class` block function provided by DrawFBP. This will bring up a `File Chooser` function, which you can use to locate `StartsWith`. In the first panel of `File Chooser`, you will see the JavaFBP jar file, followed by any other jar files you have added (using the `File/Add Additional Jar File` function), followed by the top level directories for the project you are working on.
10 |
11 | Click on the JavaFBP jar file entry, and you can start walking through its tree structure, until you find the component you need, which is in the package `com/jpaulmorrison/fbp/core/components/text`.
12 |
13 | Since different components specify different port names, you need to find out the port names used by `StartsWith`. Here are three ways that are available to do this:
14 |
15 | - go to the source code for the component in the JavaFBP repo ( `src/main/java/com/jpaulmorrison/fbp/core` ), and look at the annotations (`@OutPorts` and `@InPorts`), or
16 |
17 | - choose a component for your block in the diagram, and right click on the `Display Description and Port Info` function provided for DrawFBP blocks, which will bring up a display like the following:
18 |
19 | 
20 |
21 | Of course, if you haven't yet filled in any of the port names, this display will show `No` in the `Connected?` column.
22 |
23 | - Or look at `compList.html` by clicking on http://htmlpreview.github.io/?https://github.com/jpaulm/javafbp/blob/master/compList.html , then `Edit/Find in This Page` .
24 |
25 | **TODO: Port display for many components are missing port function annotations - these need to be filled in in JavaFBP. See issue #2**
26 |
27 | After filling in the `IN`, `ACC` and `REJ` port names, the diagram should now look like this:
28 |
29 | 
30 |
31 | If any port names have been misspelled, you will see a port name `Missing`, and another one unrecognized (`?` under `Connected?`).
32 |
33 | <== Previous / Index / Next ==>
34 |
--------------------------------------------------------------------------------
/Step03/StartsWith.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step03/StartsWith.png
--------------------------------------------------------------------------------
/Step03/Step03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step03/Step03.png
--------------------------------------------------------------------------------
/Step03/compListPart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step03/compListPart.png
--------------------------------------------------------------------------------
/Step04/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step04 - Set a value for a part
5 |
6 | Now, as shown in the port list shown above, `TEST` is the port name for the IIP which specifies the test character for matching. As stated above, IIPs are the way FBP reusable components are parameterized. Usually the parameter is specified in a network definition, so that a network can use the same component in more than one place in the network - with different parameters - but IIPs have the added advantage that the network can easily be changed to present the parameter information as a normal IP, obtained from an upstream process.
7 |
8 | In this case the parameter for `StartsWith` will be provided as an IIP, specified in the diagram. In DrawFBP just click on the button at the bottom marked `Initial IP`, after which clicking on the drawing screen will now create an IIP, and allow some text to be entered. The diagram now looks like this:
9 |
10 | 
11 |
12 | Selecting `StartWith` and clicking on `Display Description and Port Info` will verify that all ports are now correctly connected.
13 |
14 | <== Previous / Index / Next ==>
--------------------------------------------------------------------------------
/Step04/Step04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step04/Step04.png
--------------------------------------------------------------------------------
/Step05/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step05 - Choose components and set values for other parts
5 |
6 | Pretty straightforward: just click on each block, and select `Choose Component/Subnet Class`.
7 |
8 | This will present the "File Chooser" dialog. Assuming you have (successfully) used the `Locate JavaFBP Jar File` function, the first line will be the root of that jar file. Other entries will be from your working component directory. Any time you use the `Add Aditional Jar File` function, more jar files will be added to the top of the "File Chooser" file list.
9 |
10 | The first block (`read sample file`) would most probably use the `ReadFile` component in the `core/components/io` package in the JavaFBP jar file. This requires an IIP containing the file name - port name `SOURCE`.
11 |
12 | The `ignore` block would most likely use the `Discard` component in the `core/components/routing` package, although of course you could use any component here, or even route the "ignored" IPs to other parts of the diagram.
13 |
14 | That just leaves `display accepted lines`. In this example, the `ShowText` component puts up its output in a separate window, and requires an IIP with port name `TITLE`. `ShowText` has an optional port called `OUT` - if this is connected, incoming IPs are routed to this port after being displayed.
15 |
16 | Here is the final diagram:
17 |
18 | 
19 |
20 | <== Previous / Index / Next ==>
21 |
--------------------------------------------------------------------------------
/Step05/Step05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step05/Step05.png
--------------------------------------------------------------------------------
/Step06/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step06 - Generate a Java program
5 |
6 | Now we have all the necessary information filled in to generate a running program, so click on `File/Generate ... Network` - Java is the default language, so in the `File` menu, this function will show up as `Generate Java Network`. You can switch languages by clicking on `Select Diagram Language`, and this menu entry will change accordingly: currently 4 languages are supported - Java, C#, JSON and FBP.
7 |
8 | Here is the result:
9 |
10 | 
11 |
12 | DrawFBP remembers the last used package name, so it allows the developer to change it to whatever matches the directory structure - or Eclipse will prompt him/her to change it, if necessary, when the code is executed.
13 |
14 | DrawFBP's colouring of code is mostly to make character strings and comments stand out from the rest of the text.
15 |
16 | `component` and `connect` are self-explanatory! `initialize` builds an IIP, and connects it to an input port of a component.
17 |
18 | When using `Save As`, to get ready for compiling and running the FBP network, please be aware that for Java DrawFBP uses the convention of matching sub-directories under `src` (for the `.java` files) and `bin` (for the compiled `.class` files).
19 |
20 |
21 | <== Previous / Index / Next ==>
22 |
--------------------------------------------------------------------------------
/Step06/Step06_code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step06/Step06_code.png
--------------------------------------------------------------------------------
/Step06/code/Step06.java:
--------------------------------------------------------------------------------
1 | package refactoring; //change package name if desired
2 | import com.jpaulmorrison.fbp.core.engine.*;
3 | public class Step5 extends Network {
4 | String description = "Components filled in";
5 | protected void define() {
6 | component("read__sample__file",com.jpaulmorrison.fbp.core.components.io.ReadFile.class);
7 | component("filter_by__first_letter",com.jpaulmorrison.fbp.core.components.text.StartsWith.class);
8 | component("Ignore",com.jpaulmorrison.fbp.core.components.routing.Discard.class);
9 | component("display__accepted__lines",com.jpaulmorrison.fbp.core.components.swing.ShowText.class);
10 | connect(component("filter_by__first_letter"), port("REJ"), component("Ignore"), port("IN"));
11 | connect(component("read__sample__file"), port("OUT"), component("filter_by__first_letter"), port("IN"));
12 | initialize("C:/Users/bobco/drawfbp/txt-nonexist.csv", component("read__sample__file"), port("SOURCE"));
13 | initialize("J", component("filter_by__first_letter"), port("TEST"));
14 | initialize("Accepted entries", component("display__accepted__lines"), port("TITLE"));
15 | connect(component("filter_by__first_letter"), port("ACC"), component("display__accepted__lines"), port("IN"));
16 | }
17 | public static void main(String[] argv) throws Exception {
18 | new Step5().go();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Step07/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step07 - Run the program
5 |
6 | The generated code shown above is a standard JavaFBP network, and can be executed as described in https://github.com/jpaulm/javafbp/blob/master/README.md .
7 |
8 | ### Running on DOS
9 |
10 | Essentially, you will have downloaded the JavaFBP jar file earlier, so position to the `bin` directory of your project, and enter the following into the DOS window:
11 |
12 | java -cp "/javafbp-x.y.z.jar;."
13 |
14 | where `x.y.z` is the version of the jar file you downloaded in **Step0**. Note the final **;.**.
15 |
16 | should include the package ID, with periods instead of slashes, and the final `.class` should be dropped.
17 |
18 |
19 | ### Running on *nix
20 |
21 | Replace the ';' in the `-cp` parameter with ":" for *nix.
22 |
23 | ### Running in Eclipse
24 |
25 | Go to `Properties/Java Build Path` for your project; click on `Add External Jars`, add your JavaFBP jar file to the list, and then hit `Apply' and `OK`.
26 |
27 | Select `Debug` for your project.
28 |
29 |
30 | ### Set up some data
31 |
32 | Nearly forgot - we need to give it some data: ReadFile handles any sequential file. In this case the file reader's IIP names at a CSV file (https://en.wikipedia.org/wiki/Comma-separated_values ), and the selected records will appear in a separate window.
33 |
34 | <== Previous / Index / Next ==>
--------------------------------------------------------------------------------
/Step08/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step08 - Inside a component
5 |
6 | Building a component is relatively simple, but I would like to stress again that you can do a lot of the work involved in building an application without ever doing any coding! However, if you want to see what a component looks like, I have included the code for `StartsWith.java`:
7 |
8 | ### Code for a simple "filter" component.
9 |
10 | This component tests the first characters of every incoming Information Packet (IP) against a string of characters specified in an IIP which is `receive`d at port `TEST`.
11 |
12 | *Accepted* IPs are sent to port `ACC`; *rejected* IPs are sent to port `REJ`.
13 |
14 | ```java
15 | /**
16 | * JavaFBP - A Java Implementation of Flow-Based Programming (FBP)
17 | * Copyright (C) 2009, 2016 J. Paul Morrison
18 | *
19 | * This library is free software; you can redistribute it and/or
20 | * modify it under the terms of the GNU Library General Public
21 | * License as published by the Free Software Foundation; either
22 | * version 3.0 of the License, or (at your option) any later version.
23 | *
24 | * This library is distributed in the hope that it will be useful,
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
27 | *
28 | * You should have received a copy of the GNU Library General Public
29 | * License along with this library; if not, see the GNU Library General Public License v3
30 | * at https://www.gnu.org/licenses/lgpl-3.0.en.html for more details.
31 | */
32 |
33 | package com.jpaulmorrison.fbp.core.components.text;
34 |
35 |
36 | import com.jpaulmorrison.fbp.core.engine.Component;
37 | import com.jpaulmorrison.fbp.core.engine.ComponentDescription;
38 | import com.jpaulmorrison.fbp.core.engine.InPort;
39 | import com.jpaulmorrison.fbp.core.engine.InPorts;
40 | import com.jpaulmorrison.fbp.core.engine.InputPort;
41 | import com.jpaulmorrison.fbp.core.engine.OutPort;
42 | import com.jpaulmorrison.fbp.core.engine.OutPorts;
43 | import com.jpaulmorrison.fbp.core.engine.OutputPort;
44 | import com.jpaulmorrison.fbp.core.engine.Packet;
45 |
46 |
47 | /**
48 | * Select packets starting with specified string.
49 | */
50 | @ComponentDescription("Select packets starting with specified string")
51 |
52 | @OutPorts({ @OutPort(value = "ACC", description = "IPs accepted by filter"),
53 | @OutPort(value = "REJ", description = "IPs rejected by filter") })
54 | @InPorts({ @InPort(value = "IN", description = "input stream"),
55 | @InPort(value = "TEST", description = "char string being tested against") })
56 |
57 | public class StartsWith extends Component {
58 |
59 |
60 | private InputPort inport, testport;
61 |
62 | private OutputPort accport, rejport;
63 |
64 | @Override
65 | protected void execute() {
66 |
67 | Packet> testPkt = testport.receive();
68 | if (testPkt == null) {
69 | return;
70 | }
71 | String testStr = (String) testPkt.getContent();
72 | testport.close();
73 | drop(testPkt);
74 |
75 | Packet> p = inport.receive();
76 | while (p != null) {
77 | String content = (String) p.getContent();
78 | if (content.startsWith(testStr)) {
79 | accport.send(p);
80 | } else {
81 | rejport.send(p);
82 | }
83 | p = inport.receive();
84 | }
85 | }
86 |
87 | @Override
88 | protected void openPorts() {
89 |
90 | inport = openInput("IN");
91 | testport = openInput("TEST");
92 |
93 | accport = openOutput("ACC");
94 | rejport = openOutput("REJ");
95 |
96 | }
97 | }
98 | ```
99 |
100 | As you can see, there are only four sections in a component's code:
101 |
102 | * copyright information if desired
103 | * import statements
104 | * annotations: component description and port information
105 | * class header and declares for input and output port instance variables
106 | * two methods:
107 | * `execute()`
108 | * `openPorts()`
109 |
110 | `openports()` is invoked for each JavaFBP process once per run of the network; `execute()` is invoked for each *activation* of a process (see the description of FBP scheduling in the book on Flow-Based Programming).
111 |
112 | All JavaFBP components have this structure.
113 |
114 | Theoretically you can write components in any language that has an FBP implementation, but you may find yourself having to be creative to get different languages to intercommunicate... especially languages that are implemented by means of a virtual machine. We will be showing you how to do this later on in the tutorial.
115 |
116 | <== Previous / Index / Next ==>
--------------------------------------------------------------------------------
/Step08/code/StartsWith.java:
--------------------------------------------------------------------------------
1 | /**
2 | * JavaFBP - A Java Implementation of Flow-Based Programming (FBP)
3 | * Copyright (C) 2009, 2016 J. Paul Morrison
4 | *
5 | * This library is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Library General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 3.0 of the License, or (at your option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | *
14 | * You should have received a copy of the GNU Library General Public
15 | * License along with this library; if not, see the GNU Library General Public License v3
16 | * at https://www.gnu.org/licenses/lgpl-3.0.en.html for more details.
17 | */
18 |
19 | package com.jpaulmorrison.fbp.core.components.text;
20 |
21 |
22 | import com.jpaulmorrison.fbp.core.engine.Component;
23 | import com.jpaulmorrison.fbp.core.engine.ComponentDescription;
24 | import com.jpaulmorrison.fbp.core.engine.InPort;
25 | import com.jpaulmorrison.fbp.core.engine.InPorts;
26 | import com.jpaulmorrison.fbp.core.engine.InputPort;
27 | import com.jpaulmorrison.fbp.core.engine.OutPort;
28 | import com.jpaulmorrison.fbp.core.engine.OutPorts;
29 | import com.jpaulmorrison.fbp.core.engine.OutputPort;
30 | import com.jpaulmorrison.fbp.core.engine.Packet;
31 |
32 |
33 | /**
34 | * Select packets starting with specified string.
35 | */
36 | @ComponentDescription("Select packets starting with specified string")
37 |
38 | @OutPorts({ @OutPort(value = "ACC", description = "IPs accepted by filter"),
39 | @OutPort(value = "REJ", description = "IPs rejected by filter") })
40 | @InPorts({ @InPort(value = "IN", description = "input stream"),
41 | @InPort(value = "TEST", description = "char string being tested against") })
42 |
43 | public class StartsWith extends Component {
44 |
45 |
46 | private InputPort inport, testport;
47 |
48 | private OutputPort accport, rejport;
49 |
50 | @Override
51 | protected void execute() {
52 |
53 | Packet> testPkt = testport.receive();
54 | if (testPkt == null) {
55 | return;
56 | }
57 | String testStr = (String) testPkt.getContent();
58 | testport.close();
59 | drop(testPkt);
60 |
61 | Packet> p = inport.receive();
62 | while (p != null) {
63 | String content = (String) p.getContent();
64 | if (content.startsWith(testStr)) {
65 | accport.send(p);
66 | } else {
67 | rejport.send(p);
68 | }
69 | p = inport.receive();
70 | }
71 | }
72 |
73 | @Override
74 | protected void openPorts() {
75 |
76 | inport = openInput("IN");
77 | testport = openInput("TEST");
78 |
79 | accport = openOutput("ACC");
80 | rejport = openOutput("REJ");
81 |
82 | }
83 | }
--------------------------------------------------------------------------------
/Step09/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step09 - More ideas about design
5 |
6 | As you may have intuited, in FBP we like to go from a high-level design to progressively lower level networks, until we are ready to start filling in component names. These lower-level networks are called "subnets" - basically diagrams with "sticky" connections, that can both function as components but themselves comprise components - or still lower-level subnets. This keeps the visual mode of FBP without having huge networks with dozens of blocks in a single chart, so a complex application may be structured as a "tree" of subnets, where the root is a high-level network with all or most of the nodes being subnets.
7 |
8 | In fact DrawFBP has a facility called "Excise" where the designer marks off a section of the diagram and "excises" it, forming a subnet and replacing the excised subnet with a single block that instantiates the subnet. The sticky ends are called "External Ports" - more about subnets and external ports in Step12-Subnets.
9 |
10 | This style of development is usually called "top-down", but other "directions" have been found useful as well. This section is from my book:
11 |
12 | "... The data streams which tend to drive all the others are the ones which humans will see, e.g. reports, etc., so you design these first. Then you design the processes which generate these, then the processes which generate their input, and so on. This approach to design might be called 'output backwards'...."
13 |
14 | Another "direction" is one I call "centre out": again from my book: " ... the 'centre out' development approach – you can get the core logic working first, and then add formatting, input editing, etc., later."
15 |
16 | FBP also lends itself very well to rapid prototyping, and simulation as well - see the discussion about simulation systems in [Chapter I of my book](http://www.jpaulmorrison.com/fbp/intro.shtml) . You can also start with a *simulation* of your application, and gradually replace the blocks with real application functions.
17 |
18 | <== Previous / Index / Next ==>
19 |
--------------------------------------------------------------------------------
/Step10/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step10 - Extend the diagram
5 |
6 | For this step we will stay at the diagram level - these changes could of course be made to the *generated code*, but then the code would become progressively more out of step with the diagram, which is perhaps the most important tool of communication between the various groups involved in the development of an application.
7 |
8 | Let us now suppose that we want to count the number of rejected IPs before discarding them. Surprise! We happen to have a Counter component in our bag of tricks: a count IP goes to one output port, incoming IPs are routed to the other (optional) output port.
9 |
10 | Here is the modified diagram (we are showing it without the components or port names filled in - to stress that this is happening at the high level design stage):
11 |
12 | 
13 |
14 | Here is the segment of [compList](http://htmlpreview.github.io/?https://github.com/jpaulm/javafbp/blob/master/compList.html) that gives the port names for Counter:
15 |
16 | 
17 |
18 | As you have probably figured out, the counter *creates* a count IP and sends it out.
19 |
20 | Port `OUT` is marked *optional*. `Counter` tests if this port is connected - and, if not, it discards IPs that are sent to this port. In what follows, we will drop the `Ignore` block.
21 |
22 | <== Previous / Index / Next ==>
--------------------------------------------------------------------------------
/Step10/Step10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step10/Step10.png
--------------------------------------------------------------------------------
/Step10/counter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step10/counter.png
--------------------------------------------------------------------------------
/Step11/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step11 - Combine data flows
5 |
6 | Now you will have noticed that there are two `Display` blocks - if you use a windowing component like `ShowText`, you will see two windows; if you use console components the outputs may be intermingled - remember that FBP is totally asynchronous. So maybe we want to combine the outputs, with the count following the accepted IPs. Our first attempt might look like this:
7 |
8 | 
9 |
10 | The count cannot be generated until the inputs have all been read, so the various outputs should be displayed in the right order, but the generated count could wind up intermixed with the "accepted" stream if certain changes are made to the network. So we should really ensure that the count is not displayed until after *all* the accepted IPs have been displayed. We do this using the `routing.ConcatStreams` component, as follows:
11 |
12 | 
13 |
14 | `ConcatStreams` reads and outputs all of its first input, followed by the second input, and so on. If `ConcatStreams` could only handle, say, two input streams, it might call them `IN1` and `IN2`, but it can handle any number, so it uses something called an "array port", and the individual connection points are labelled using an indexing notation, e.g. `IN[0]`, `IN[1]`, and so on.
15 |
16 | <== Previous / Index / Next ==>
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Step11/Step11-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step11/Step11-2.png
--------------------------------------------------------------------------------
/Step11/Step11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step11/Step11.png
--------------------------------------------------------------------------------
/Step12/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step12 - Subnets
5 |
6 | As we stated above, FBP has a concept called "subnets", which may be thought of as ordinary FBP networks, but with "sticky" connections. FBP supports a "top-down" approach to developing applications, where design goes from a high-level design, initially with no components filled in, to progressively lower levels. At some point later, we can start filling in component names. These lower-level networks are called "subnets" - basically diagrams that can both function as components but themselves will comprise components or still lower-level subnets - so a complex application will typically be structured as a "tree" of subnets, where the root is a high-level network with all or most of the nodes being subnets.
7 |
8 | Of course, during the design process, the developer will also at times be working "upwards" from the component level (more so in the later - and "lower" - stages of design). Imagine designing a house: working down from the highest level, you do not suddenly find drywall emerging magically from the design: drywall is one of the components in your "bag of tricks", and at some point you realize that drywall will be useful, and you start adapting your design to start working with that in mind. If, at some point in the design, you decide you are going to go with concrete block, the design will take a different path.
9 |
10 | Continuing this analogy a bit, the higher levels of the design for a house probably do not care whether you are eventually going to choose drywall or concrete block - after all, houses will always need a roof, walls, a front door, windows, etc. It will be somewhere around the "halfway mark" in the design process that the above decision will start to impinge on the design, and your design will have to go one of two ways. Unlike conventional programming, FBP is very strongly component-oriented, so the FBP practitioner will always be bearing in mind which components are available - and trying to add components to the FBP "bag of tricks" to benefit other users.
11 |
12 | Now, going back to subnets: a designer can certainly build each subnet by hand (there is an example in https://github.com/jpaulm/javafbp/blob/master/src/main/java/com/jpaulmorrison/fbp/resourcekit/examples/subnets/InfiniteQueue.java - look for instances of `SUBIN` and `SUBOUT`), but it could be tricky to get it right, so DrawFBP has a facility called "Excise" where the designer marks off a section of the diagram and "excises" it, forming a subnet and replacing the excised subnet with a single block that represents the whole subnet. The sticky ends are called "External Ports", and form a bridge between the inside and the outside of a subnet. Subnets thus partake of both the nature of networks and components.
13 |
14 | Let us go back to the diagram we show in Step05-Choose components and fill in values for other parts:
15 |
16 | 
17 |
18 | Now let us suppose we want to turn the two centre processes into a subnet - this will also have the benefit of hiding the "Ignore" node - we will call the subnet called "Filter".
19 |
20 | The way we do this is to create an instance of the "Enclosure" block type, and *stretch* it to surround the blocks we want to excise - mouse over the corners, and drag them to where you want them to be. Here is the diagram with the Enclosure added.
21 |
22 | 
23 |
24 | You will see that three of the arrows in this diagram are crossed by the dotted lines: these are the connections which connect the inside and the outside of the Enclosure, so the Excise function will add "External Ports", and hook up these connections to them. External ports are actually processes in their own right, but have a different symbol on the diagram. The single block that will replace the old subnet in the original diagram is shown with double line boundaries to show it is a subnet.
25 |
26 | Now the only part of the Enclosure which you can click on to get the action list is the coloured section at the top. So the best way to grasp this logic is to start by clicking on this, and then select the `Excise Subnet` function. Let's do it!
27 |
28 | The first thing that happens is that Excise will prompt you to provide a subnet name. It does not need an extension, so "Filter" will do.
29 |
30 | Next you will be prompted to enter External Port names. These are the port names that the connections with *outside* processes will use. These external ports are show with a particular symbol, and their *external* names are shown in red. During this process, the External Port you are being prompted about is shown in yellow. In case you were wondering, the *internal* names of these external ports are standard, so they are not shown.
31 |
32 | Here is the last External Port with its assigned name (the order in which you are prompted for External Port names is somewhat random!):
33 |
34 | 
35 |
36 | The actual code for `Filter.java` can be seen at [Code for "Filter"](code/Filter.java). Note that the input External Ports both use a standard component `SubIn`, while the output External Port uses component `SubOut`. The External Port *name* is passed to the process via an IIP.
37 |
38 | The External Port symbol may be thought of as a kind of visual shorthand, as all the parts are predetermined except for the external names. Here is a diagram showing an External Port "blown up" - it also shows the port information:
39 |
40 | 
41 |
42 | And here is the original diagram with the subnet replaced by a single (subnet) block:
43 |
44 | 
45 |
46 | DrawFBP will now let you modify both the subnet and what we might call the "supranet" - its parent - you can double-click on the subnet block to switch your view to the subnet itself.
47 |
48 | In the "supranet" there is now a reference to a subnet, which is a `.drw` file. To generate Java code, *all* the nodes in a diagram must have a Java `.class` file associated with them as well. So *for the new subnet*, do a `File/Generate Java Network`, followed by a `File/Compile`. Now associate the `.class` file with the subnet block, using the `Block/Choose Component or Subnet Class` - this will result in the display shown below. You can now generate the Java code for the "supranet". Here is the display showing both the `.class` file and the subnet `.drw` file for the subnet block.
49 |
50 | 
51 |
52 |
53 | <== Previous / Index / Next ==>
54 |
--------------------------------------------------------------------------------
/Step12/Step12-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step12/Step12-1.png
--------------------------------------------------------------------------------
/Step12/Step12-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step12/Step12-2.png
--------------------------------------------------------------------------------
/Step12/Step12-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step12/Step12-3.png
--------------------------------------------------------------------------------
/Step12/Step12-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step12/Step12-4.png
--------------------------------------------------------------------------------
/Step12/Step12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step12/Step12.png
--------------------------------------------------------------------------------
/Step12/code/Filter.java:
--------------------------------------------------------------------------------
1 | package refactoring; //change package name if desired
2 | import com.jpaulmorrison.fbp.core.engine.*;
3 | @ComponentDescription("Filter")
4 | @InPorts({@InPort("IN"), @InPort("PARM")})
5 | @OutPort("OUT")
6 |
7 | public class Filter extends SubNet {
8 | String description = "Filter";
9 | protected void define() {
10 | component("SUBIN",SubIn.class);
11 | initialize("IN", component("SUBIN"), port("NAME"));
12 | component("SUBIN_2_",SubIn.class);
13 | initialize("PARM", component("SUBIN_2_"), port("NAME"));
14 | component("filter_by___first__letter",com.jpaulmorrison.fbp.core.components.text.StartsWith.class);
15 | component("ignore",com.jpaulmorrison.fbp.core.components.routing.Discard.class);
16 | component("SUBOUT",SubOut.class);
17 | initialize("OUT", component("SUBOUT"), port("NAME"));
18 | connect(component("filter_by___first__letter"), port("ACC"), component("SUBOUT"), port("IN" ));
19 | connect(component("SUBIN"), port("OUT"), component("filter_by___first__letter"), port("IN"));
20 | connect(component("SUBIN_2_"), port("OUT"), component("filter_by___first__letter"), port("TEST"));
21 | connect(component("filter_by___first__letter"), port("REJ"), component("ignore"), port("IN"));
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Step13/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Step13 - "Brackets" and "substreams"
5 |
6 | ### Grouping records
7 |
8 | Up to now we have been dealing with "streams" of data chunks called "Information Packets" (IPs), but very often we want to subdivide the IP stream into smaller (often nested) groupings. We call them "substreams", and they are delimited by special non-data IPs called "open bracket" and "close bracket".
9 |
10 | Here is an example from the book "Flow-Based Programming" (Fig. 9.1). We show a typical sequential file, with two levels of groupings: branch, and account. Note that there are often no special records showing the beginning or end of a grouping - this often has to be detected by changes in "control fields".
11 |
12 | ```
13 | IP type branch acct # date amount DEP/WD
14 |
15 | account 1 1
16 | trans 1 1 1992/3/12 12.82 DEP
17 | trans 1 1 1992/3/12 101.99 WD
18 | trans 1 1 1992/3/12 43.56 WD
19 | trans 1 1 1992/3/26 54.77 WD
20 | trans 1 1 1992/3/26 12.26 WD
21 |
22 | account 1 2
23 | trans 1 2 1992/3/03 34.88 DEP
24 | trans 1 2 1992/3/03 10.00 WD
25 | .
26 | .
27 | .
28 |
29 | account 2 1
30 | trans 2 1 1992/2/29 25.99 DEP
31 | trans 2 1 1992/3/25 87.56 DEP
32 |
33 | account 2 3
34 | trans 2 3 1992/3/01 34.88 WD
35 | trans 2 3 1992/3/17 88.22 DEP
36 | .
37 | .
38 | ```
39 |
40 | The "IP type" is the class of each IP contents. In this case, in FBP, the first thing we usually do is to insert an "open bracket" IP at the start of every "branch" and "account", and a "close bracket" at the end of every "account" and "branch".
41 |
42 | In conventional programming much of the processing takes place when a control field *changes*, so it is actually very helpful to have an explicit data item (an IP) signalling the point where such a change occurs!
43 |
44 | FBP has a standard component to insert the brackets at the right places ["Collate"](https://github.com/jpaulm/javafbp/blob/master/src/main/java/com/jpaulmorrison/fbp/core/components/misc/Collate.java). While the name suggests two or more input streams, you can just as well use it with one input stream.
45 |
46 | Schematically we can show the output as follows, using angle brackets for the "bracket" IPs (you can generate your brackets with tags describing what kind of group they designate, even though this is not strictly necessary):
47 |
48 | ```
49 | < (branch)
50 | < (account)
51 | account 1 1
52 | trans 1 1 1992/3/12 12.82 DEP
53 | trans 1 1 1992/3/12 101.99 WD
54 | trans 1 1 1992/3/12 43.56 WD
55 | trans 1 1 1992/3/26 54.77 WD
56 | trans 1 1 1992/3/26 12.26 WD
57 | > (account)
58 | < (account)
59 | account 1 2
60 | trans 1 2 1992/3/03 34.88 DEP
61 | trans 1 2 1992/3/03 10.00 WD
62 | .
63 | .
64 | .
65 | > (branch)
66 | < (branch)
67 | < (account)
68 | account 2 1
69 | trans 2 1 1992/2/29 25.99 DEP
70 | trans 2 1 1992/3/25 87.56 DEP
71 | > (account)
72 | < (account)
73 | account 2 3
74 | trans 2 3 1992/3/01 34.88 WD
75 | trans 2 3 1992/3/17 88.22 DEP
76 | .
77 | .
78 |
79 | .....
80 | ```
81 |
82 | The IPs between an "open bracket" and a "close bracket" comprise a "substream", so you can see that the two "branch substreams" actually each contain 2 "account substreams".
83 |
84 | ### Interactive applications
85 |
86 | A major use of substreams is in building interactive applications. Interestingly Facebook has recently announced what appears to be a rather similar design approach, called "Flux" - [Flux: An Application Architecture for React](https://reactjs.org/blog/2014/05/06/flux.html) . The FBP approach to designing interactive applications is described in more detail in Step14. Actually, we should describe this as "one approach"...
87 |
88 |
89 | <== Previous / Index / Next ==>
90 |
--------------------------------------------------------------------------------
/Step14/ClientServer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step14/ClientServer.png
--------------------------------------------------------------------------------
/Step14/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Step14 - Interactive Applications
4 |
5 | ### Overall design
6 |
7 | Another interesting application of bracket IPs is in interactive applications. In this case, typically the application end user sends something to the system, and then waits for a result. We thus have a very high level diagram that looks like this:
8 |
9 | 
10 |
11 | You will notice that we have split the user interaction into two processes: "Send to program" and "send to human" - this allows IPs being sent to the program from different users to be interspersed... and similarly for data returning to humans. If these two processes had been combined into a single process, it would have had to wait while a human handled the previous response from the machine... and human think time is *much* slower than machine think time! With separated processes, you will now have data connected with different users chasing each other round the network. Of course substreams have to be kept intact, which is why the [LoadBalancer](https://github.com/jpaulm/javafbp/blob/master/src/main/java/com/jpaulmorrison/fbp/core/components/routing/LoadBalance.java) component now sends all IPs in a substream to the same output port...
12 |
13 | This approach seems a good match with substreams. It makes sense to have the first IP in each substream contain information about the context or source of the transaction, e.g. user ID, date and time, maybe language, etc., followed by zero or more IPs containing relevant data being sent to or from the application. Substreams are a good way to represent lists, for example when you want to display all the college courses a student has taken...
14 |
15 | There is a practical example of this architecture in the [Web Sockets](https://github.com/jpaulm/javafbp-websockets) repository. Here we split the above diagram between client and server. The client code is written in HTML and JavaScript and simply sends a request substream across the sockets connection, and then displays the resulting list substream. `Receive` and `Respond` are simple "off the shelf" FBP components, and the subnet can be any combination of components and subnets which produce a result substream which will be processed by `Respond`. As stated above, you can do anything - as long as substreams are not broken up! I have copied the schematic from [Web Sockets](https://github.com/jpaulm/javafbp-websockets):
16 |
17 | 
18 |
19 | "WS" of course stands for Web Sockets.
20 |
21 | I realize this may seem rather simple, but a real-life example will of course be more complex... and there are a number of ways performance can be improved, as e.g. by multiplexing (using the [LoadBalancer](https://github.com/jpaulm/javafbp/blob/master/src/main/java/com/jpaulmorrison/fbp/core/components/routing/LoadBalance.java), as shown in the diagram at the end of [JavaFBP-WebSockets](https://github.com/jpaulm/javafbp-websockets/blob/master/README.md)), use of caches, etc.
22 |
23 |
24 | ### Database access
25 |
26 | Now let's consider what is going on at the "back end" of this diagram...
27 |
28 | So far I have just drawn a single subnet processing input, but of course most applications will need to access data... By the rule of separation of concerns, we naturally use a separate I/O component, which we will call "Database Access", so we will add that into the diagram (using the simpler diagram above), as follows:
29 |
30 | 
31 |
32 | (The disk icon is just a visual clue - it will not result in any code being generated)
33 |
34 | You will notice that Database Access has an input port *and* an output port, so it is equivalent (in this diagram) to a subroutine call... Quoting Prof. Gelernter (Linda),
35 |
36 |
37 | In our experience, processes in a parallel program usually don’t care what happens to their data, and when they don’t, it is more efficient and conceptually more apt to use an asynchronous operation like Linda’s “out” than a synchronous procedure call.... It’s trivial, in Linda, [or FBP - my comment] to implement a synchronous remote-procedure-call-like operation in terms of “out” and “in” [FBP “send” and “receive”]. There is no reason we know of, however, to base an entire parallel language on this one easily programmed but not crucially important special case.
38 |
39 |
40 | You may be wondering why we don't use a subroutine call, but we don't want to wire the name of the Database Access function into the caller's code. Not even Object-Oriented does that! But, more importantly, Database Access can operate both in "call" mode, and in "flow-through" mode. See Gelernter above: "...processes in a parallel program usually don’t care what happens to their data."
41 |
42 | Schematically:
43 |
44 | 
45 |
46 | In the above diagram, I have shown "Process" as a single block communicating with a single I/O block - this means that, in this instance, I/O is essentially synchronous and can only handle one user at a time. Of course, I/O is generally slower than computation, so this works if accesses to the relevant database are not very frequent. If they are, we will want to adopt techniques for spreading the load - on such is the LoadBalancer alluded to above, which will allow multiple users to do access the same database concurrently. This in turn means that provision should be made for handling I/O deadlocks, as one user may be trying to write a data block, while another reads it or writes it. There is a whole chapter on this in the book on [Flow-Based Programming: 2nd ed.](https://jpaulm.github.io/fbp/book.html) - Chap. XIX: Synchronization and Checkpoints.
47 |
48 | Another way to improve I/O performance is to take advantage of the "80/20" rule, and add a caching component upstream from the I/O...
49 |
50 | In the diagram, coding "Process" as a single block allows the process to retain data across the database access. However, where RESTful conventions are followed, this should not be necessary. This also allows at least part of the database processing to be offline. As this might take a while, one might split the "Process" block and provide some kind of index to keep track of in-process data requests and relate the output of Database Access to its input.
51 |
52 | We will also want to make the I/O component(s) reusable, which involves establishing a "contract" between it/them and any upstream components. Some efforts at standardization should be undertaken... I am suggesting that there should be at minimum:
53 |
54 | - a GET protocol: incoming IP specifies a key; outgoing IP contains zero or more result IPs
55 |
56 | - a PUT protocol: incoming IP specifies a key, following IPs contain data; outgoing IP indicates success or failure - this either updates data or creates new data
57 |
58 | - a DELETE protocol: incoming IP specifies a key; outgoing IP indicates success or failure
59 |
60 | Clearly, different users' substreams will follow each other (without splitting substreams) through the I/O subsystem.
61 |
62 | After all this verbiage, we are going to try a little artwork. I'm afraid it's a bit wide, but here goes:
63 |
64 | 
65 |
66 | The path marked BYPASS1 represents data being processed that does not need to access the database; the path marked BYPASS2 represents data being processed that needs to take another pass through the database.
67 |
68 |
69 | <== Previous / Index / Next ==> (none)
70 |
--------------------------------------------------------------------------------
/Step14/Step14-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step14/Step14-1.png
--------------------------------------------------------------------------------
/Step14/Step14-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step14/Step14-2.png
--------------------------------------------------------------------------------
/Step14/Step14-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step14/Step14-3.png
--------------------------------------------------------------------------------
/Step14/Step14-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/Step14/Step14-4.png
--------------------------------------------------------------------------------
/bottling_factory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/fbp-tutorial-filter-file/c8d7e6075e9f7ec72a08762bd66aae104e5bf0e6/bottling_factory.png
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | .middle {
2 | display: block;
3 | margin: auto;
4 | width: 70%;
5 | }
6 |
--------------------------------------------------------------------------------