Creating Flow Charts

Triggers

Once a flow chart object has been created, you need to create either a trigger or an action. Commonly, flow charts start with a Timer Trigger and then flow into different actions. In this manner, the flow chart will wait until a specified time and date arrives before executing specific actions.

Triggers wait for some event to occur, and then fire. By waiting for a specific time, for a message to arrive, or for some other event to occur, successive actions in your flow chart will execute in the correct order.

After a trigger fires, control flows into a different action or trigger and execution of the flow chart continues.

The triggers that Flux supports are detailed beginning in (cross reference) .

Triggers can return variables. These variables are placed into a flow context, which is an object that represents the state of the flow chart as a thread of execution passes through the flow chart. Successive triggers and actions can access this flow context to retrieve data generated by earlier triggers and actions.

Actions

Within flow charts resides a large number of actions Flux provides, all with various functionality. If needed, you can also write your own custom actions that better conform to your businesses needs. Below are detailed descriptions of these actions.

In general, actions perform some function.

For details on how to write a custom trigger or action and use it like any other trigger or action in Flux, see Custom Triggers and Actions. You can use custom triggers and actions at the Flux API level as well as in the Flux Designer and Web-based Designer.

Flow Charts that Start with an Action

Even though it is very common for flow charts to start with a Timer Trigger, you can also start your flow charts off using actions. Suppose that you have a long-running flow chart and you want to run it in the background of your application. By constructing a flow chart that starts with an action, you can schedule your flow chart to run in the background, as soon as sufficient resources are available.

Flows

By default, the first trigger or action that is made from a flow chart is the first to execute when the flow chart starts executing. However, after that first trigger or action executes, control must flow into a different trigger or action. Flows allow you to specify these connections.

For example, to build a flow chart that starts with a Timer Trigger and flows into a Java Action, you need to define a flow from the Timer Trigger to the Java Action.

This code creates a flow from the Timer Trigger into the Java Action. After the Timer Trigger fires, control flows into the Java Action.

TimerTrigger timerTrigger = flowChart.makeTimerTrigger("My Timer Trigger");
...
JavaAction javaAction = flowChart.makeJavaAction("My Java Action");
...
timerTrigger.addFlow(javaAction);

Let's take this example a bit further. Suppose you wish to define a flow chart that executes a Java Action every five seconds, indefinitely. The above flow chart will execute your Java Action only once. To allow your Java Action to execute again after another five seconds, you must add a flow from the Java Action back up to the Timer Trigger.

javaAction.addFlow(timerTrigger);

In this manner, your Java Action will fire every five seconds, indefinitely.

Continuing with this example, suppose you want this Java Action to fire for a total of ten firings. To add in this restriction, you need to set a count on the Timer Trigger.

timerTrigger.setCount(10);

After the Timer Trigger fires ten times, control will not flow into the Java Action. Instead, it branches down a specialexpiration flow. This expiration flow allows you to perform different actions. Or, in the simplest case, your flow chart can terminate.

Here is a complete example. This example may seem a bit long, but it’s basic. Just paste it into your text editor, compile, and run it.

import flux.ActionListener;
import flux.Engine;
import flux.EngineHelper;
import flux.Factory;
import flux.FlowChart;
import flux.JavaAction;
import flux.KeyFlowContext;
import flux.TimerTrigger;
 
public class CompleteExample
 
public static void main(String[] args) throws Exception {
 
    Factory fluxFactory = Factory.makeInstance();
    EngineHelper helper = fluxFactory.makeEngineHelper();
    FlowChart flowChart = helper.makeFlowChart("My Flow Chart");
    TimerTrigger trigger = flowChart.makeTimerTrigger("My Trigger");
    trigger.setTimeExpression("+1s");
    trigger.setCount(10);
    JavaAction action = flowChart.makeJavaAction("Normal Action");
    action.setListener(MyJobListener.class);
    action.setKey(new MyJobKey("My Job Data"));
    trigger.addFlow(action);
    action.addFlow(trigger);
 
    // The above code creates a job that fires a Java Action every
    // five seconds for a total of ten firings.
    // Now create an expiration flow to an expiration action.
    JavaAction expired = flowChart.makeJavaAction("Expired Action");
    expired.setListener(AnotherJobListener.class);
    expired.setKey(new AnotherJobKey("More Job Data"));
 
    // Finally, after the Timer Trigger has fired ten times,
    // flow into a different part of the flow chart. You are free
    // to add more actions and triggers after the "expired" action
    // executes.
    trigger.setExpirationFlow(expired);
 
    // Now we have defined our job. To see this job fire,
    // create an engine, start it, and then add this job
    // to the engine.
    Engine scheduler = fluxFactory.makeEngine();
    scheduler.start();
    scheduler.put(flowChart);
 
    // Give the example job a chance to run.
    Thread.sleep(15000);
 
    // Finally, shut down the scheduler and exit.
    scheduler.dispose();
 
  // main()
 
  // A job listener that executes Java code when called.
  public static class MyJobListener implements ActionListener
 
    public Object actionFired(KeyFlowContext flowContext) throws Exception {
 
      System.out.println("MyJobListener has fired.");
      System.out.println("Your code goes here.");
      return null;
 
    // actionFired()
 
  // class MyJobListener
 
  // Another job listener that executes Java code when called.
  public static class AnotherJobListener implements ActionListener
 
    public Object actionFired(KeyFlowContext flowContext) throws Exception {
 
      System.out.println("AnotherJobListener has fired.");
      System.out.println("Your code goes here.");
      return null;
 
    // actionFired()
 
  // class AnotherJobListener 
 
  // Holds job data.
  public static class MyJobKey {
 
    // The actual job data.
    public String myJobData;
 
    // The default constructor.
    public MyJobKey() { } // constructor
 
    // Initializes the job data object.
    public MyJobKey(String keyData) {
 
      this.myJobData = keyData;
 
    // constructor
 
  // class MyJobKey
 
  // Holds more job data.
  public static class AnotherJobKey {
 
    // The actual job data.
    public String moreJobData;
 
    // The default constructor.
    public AnotherJobKey() { } // constructor
 
    // Initializes the job data object.
    public AnotherJobKey(String keyData) {
 
      this.moreJobData = keyData;
 
    // constructor
 
  // class AnotherJobKey 
 
// class CompleteExample

This last example, while a little more complex, shows the expressive power of modeling jobs as flow charts. You can create flow charts that truly model the complexity of your job requirements. The above flow chart executes a Java Action 10 times by creating a loop in the flow chart. After the tenth execution, flow then branches down a new path, where new actions and triggers can be executed and fired.

Conditional Flows

Triggers and actions can return results. Depending on those results, control can branch to different triggers and actions. These conditional branches are called conditional flows. Until now, all flows were unconditional. That is, they were always taken regardless of the previous result.

Conditions are evaluated using an expression language that evaluates _variables. _A persistent variable is simply a Java object that contains public fields. Those public fields are automatically stored and retrieved from your database.

Triggers and actions can return such variables. Conditions can then test those persistent variables to determine if the flow chart should branch in one direction or another. By convention, the name of a variable that a trigger or action returns is named result. If the previous trigger or action returned a variable that contains a public field named istrue, then you can build an expression that uses that information:

result.istrue

When building your flow chart, you must be aware of the kinds of variables that triggers and actions can return. With this knowledge, you can create a conditional expression that references particular public fields in a persistent variable that was returned by a previous action or trigger. The following code illustrates this capability.

timerTrigger.addFlow(javaAction, "result.istrue");

Control flows from the Timer Trigger to the Java Action only if the condition result.istrue is satisfied, otherwise, that flow is not followed. You can add any number of such conditional flows leading from one action or trigger to another.

In general, you do not need to hard code the string result. Instead, you can use a method from the EngineHelperhelper object.

timerTrigger.addFlow(javaAction, EngineHelper.useLastResult("istrue"));

These two conditional flows are equivalent.

These conditional expressions can test fields that are of any basic type, including strings, booleans, integers, floats, and so on. A string expression is satisfied if it contains the word true. Case is ignored. A simple boolean expression is satisfied if it contains the value true. Similarly, the numerical expressions are satisfied if they contain a non-zero value.

In the above examples, it is not known whether result.istrue is a string, a boolean, or a numerical type. It does not matter. The conditional expression is evaluated regardless of its underlying type.

Conditional Flow Syntax

You can create conditional expressions very similar to the WHERE clause of SQL queries. It is possible to write conditional expressions like result.salary >= 5000, evaluate multiple variables in your flow context like (result.salary >=5000) AND (result.age != 20), evaluate data contained in a java.util.Map, and other types of complex expressions.

Conditional flows can be created using the sytax described in the following table. You can mix and match these operators and use multiple variables to create complex statements that accurately describe your requirements.

Conditional Expression / Message Selector Syntax

Operators

Description

=

Equal To

>

Greater Than

<

Less Than

>=

Greater Than or Equal To

<=

Less Than or Equal To

<>

Not Equal To

+

Addition

-

Subtraction

*

Multiplication

/

Division

%

Wildcard character for use with LIKE

LIKE

Test whether a pattern appears in a string or variable (requires the wildcard character, '%', to be used in the pattern)

NOT

TRUE if the conditional expression evaluates to FALSE

AND

TRUE if all conditional expressions evaluate to TRUE

OR

TRUE if any conditional expression evaluates to TRUE

IN

TRUE if your value exists within a collection of values

mapname[‘keyname’]

Evaluates data stored under the name "keyname" in a map with the name "mapname"

.

Evaluates public fields in the value.

Strings are denoted using single 'tick' characters, such as 'this is my string'. For example, to test if a result variable is equal to a particular string, you could write the following: result.name = 'my name here'

Note: there is no way to include a single 'tick' character within the string itself. The 'tick' characters (single quotation marks) can appear only on the left and right edges of your string. For example, it is impossible to describe a string that contains an apostrophe, like so: my friend's name here

Else Flows

An Else Flow is followed if there are no unconditional flows and none of the conditional flows were satisfied. There can be at most one Else Flow branching out of a trigger or action.

javaAction.setElseFlow(anotherJavaAction);

Looping Flows

In Flux, a "loop" occurs any time a trigger or action (or a group of triggers or actions) runs more than once during the execution of a flow chart. In other words, a loop allows you to run one or more triggers or actions repeatedly within a flow chart.

In order to create a loop, you'll need to design your flow chart to allow your triggers and actions to run more than once. Because Flux uses the flow chart model to define workflows, every trigger and action in Flux can only move on to the next step in the workflow if there is a flow for it to follow. If there are no outgoing flows from a trigger or action, the workflow (and the flow chart) will end at that point, and the flow chart is considered to have finished (and will then be automatically removed from the engine).

To create a loop, therefore, you just need to be sure that the last trigger or action in the loop has a flow going back to the trigger or action that should begin the loop. This will instruct Flux to go back and re-execute the first trigger or action in the loop once the final item has complete, then follow the flows through the loop again as normal, looping back once more once the final trigger or action has run.

Keep in mind that if a trigger or action does have an outgoing flow, but the flow is a conditional flow that is not satisfied during a particular run, that flow will not be followed on the run. If there are no other flows that can be followed, the flow chart will stop running at that point.

This same behavior can be used to "break" a loop at a particular time. You can simply create a flow context variable containing a flag that indicates whether the loop should keep running, then use conditional flows to check the value of the variable. If the variable is "true", follow a conditional flow that keeps the loop running, and if it's "false", follow another conditional flow to a different set of actions (or end the flow chart altogether).

In sort: triggers and actions in Flux will follow any outgoing flows (as long as they are not conditional flows whose conditions aren't satisfied). You can use this behavior to loop backward in your flow chart and create a chain of triggers and actions that runs repeatedly, or until a condition that you define causes the loop to exit.

Error Flows

Error flows allow you to control how errors are handled on a per-action level. You can find more information about error flows in the Error Handling documentation.

Custom Error Handlers

Custom error handlers are specialized flow charts that allow you to define how a flow chart reacts to errors. If an action throws an error and does not have an error flow to follow, it will invoke the custom error handler is invoked.

The Error Handling documentation contains more information about creating and installing custom error handlers.

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.