Custom Actions

VERSION 2 Published

Created on: 09-Nov-2007 13:09 by flux - Last Modified:  26-Feb-2008 16:11 by Guest

There are 42 actions and triggers within Flux, but in some specialized implementations, this still is not enough to fully cover every idiosyncrasy you are developing a solution for. The Java Action is provided to implement one-use pieces of code. If you find yourself reusing the same listener class for your Java Actions repeatedly, or if there is just one action missing from the Flux library that would make your job flow perfectly, you may want to consider building your own custom action or suite or actions. If you want to execute a flow chart based on a condition that is not represented in the built-in Flux
triggers, and you can detect this condition programmatically, you may want to consider implementing a custom trigger.

This guide will walk through creating a basic custom action and custom trigger and briefly touch on a good implementation and design techniques. With a good understanding of custom action and triggers, your use of Flux will become boundless.

Note: Custom Actions and Triggers require some programming knowledge; if you are mainly using Flux from an end user’s perspective and not as a software developer, this guide will be of little use.

Getting Starting: Making a Factory Class

As is evident if you have spent some time working with the Flux API, the Flux framework is deeply entwined with the Factory design pattern. When
you build a suite of custom actions of triggers, it would be beneficial to create your own Factory class to preserve the integrity of this design implementation. Doing so is relatively simple and can be achieved by following the steps below.

  • Create a class that implements the flux.dev.AdapterFactory interface. This class will subsequently need to implement the init(FlowChartImpl flowchart) method. Writing this class can be as simple as in the code below:
import flux.dev.AdapterFactory;
import fluximpl.FlowChartImpl;
 
public class MyCustomFactory implement AdapterFactory{
    private FlowChartImpl flowchart;
        void init(FlowChartImpl flowchart){
        this.flowchart = flowchart
    } 
}


The FlowChartImpl object passed into the init method will be used to link your Actions and triggers to a specific flow chart, so be sure to save it in a field.

  • Write "make" methods in your factory to instantiate the custom actions and triggers you have built. A sample is provided below.
public MyCustomAction makeCustomAction(String name){
    return new MyCustomActionImpl(flowchart, name);
} 

  • To make it so you will be able to create an instance of the factory through the makeFactory(String) method on the FlowChart object, you will need to create a file called "factories.properties",open it with a text editor, and add an entry for your factory class. The format for the entry is "ShortName=FactoryClass", for example:
TestFactory=product.flux.MyFactory

The short name ("TestFactory" in the case of the above example) must not conflict with prebuilt Flux factories such as "gui", "file", or "messaging".\\\\ Ensure this file is visible to your application by either including it in the java classpath, root directory, or system classpath.\\\\ Now when you are writing code with the Flux API, your custom actions and triggers will be accessible through a factory that is created through the makeFactory(String) method on an instance of the FlowChart object. For example:\\\\
MyFactory myFactory = (MyFactory) flowChart.makeFactory("TestFactory"); 
MyCustomAction myCustomAction = myFactory.makeMyCustomAction("MyAction1");


Custom Actions

Designing actions in Flux follows a basic design pattern. An action starts as a base interface that contains getters and setter methods for the action properties as well as any additional information that the action can receive or process. From here an implementing class is created, usually with the same name as the interface only with "Impl" added to the end (if "MyAction" is the interface, "MyActionImpl" would be the implementing class). This class is instantiated through a factory class via a make method (see the section above this for implementation details on this action). Basic implementation of this pattern will be discussed in the steps that follow.

  • A basic interface will need to be created that extends the interface flux. Action contains getter, setter, and toggling methods for your action's properties. In this guide we will be building an action that will allow the user to execute a batch of MYSQL commands:
public interface SQLExecuteAction extends flux.Action{
    void addQuery(String sqlQuery); 
    void removeQuery(String sqlQuery); 
    void clearQueries();  	
}

  • Create classes that implement Serializable for your persistent variables. For example, if you are keeping a list of SQL queries as in the example provided with this guide, use the class below as a guide.

public class QueryVariable implements Serializable 
{ 
    public ArrayList <String> queries;  
    public QueryVariable(){      
    }
    public void addQuery(String query){
         if(queries == null)
        queries = new ArrayList<String>();
        queries.add(query);      
    }
    public boolean removeQuery(String query){  
        if(queries == null)
        return false;
        return queries.remove(query);
    }
    public void clearQueries(){
        queries = null;      
    }  
}  

  • Create a class that extends fluximpl.ActionImpl and implements the interface made in step 1. In addition to the methods you included in your interface, you will need to implement:

    • A constructor that calls the super(FlowChartImpl, String) method.
    • getHiddenVariables() - Returns a Set object containing the names of your persistent variables.
    • verify() - throws EngineException, FileActionException - Verifies the integrity of the object, and whether or not it is able to be executed if the flow chart is added to an engine. If not, throws either an EngineException or FileActionException.
    • execute() - The actual execution of the action. This method is called when flow reaches the object in the flow chart.
  • Consider the following implementation for the SQLExecuteAction created in step 1
import fluximpl.ActionImpl;
import fluximpl.FlowChartImpl;
import java.util.Set;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import flux.EngineException;
import flux.FlowContext;
import flux.file.FileActionException;
 
public class SQLActionImpl extends ActionImpl implements SQLAction {
    public static final String QUERY = "queries";
 
    public SQLActionImpl(FlowChartImpl fc, String s){
        super(fc, s);
    }    // Getters and Setters.
    
    public QueryVariable getVariable(){
        if(!getVariableManager().contains(QUERY))
            getVariableManager().put(QUERY, new QueryVariable());
            return (QueryVariable) getVariableManager().get(QUERY);
    }   //getVariable()
 
    public void putVariable(QueryVariable qv){
        getVariableManager().put(QUERY, qv);
    }  // Methods required by the abstract class ActionImpl     
 
    public Set getHiddenVariableNames(){
        Set set = new HashSet();
        set.add(QUERY);
        return set;
    }  //getHiddenVariableNames()    
 
    public void verify() throws EngineException, FileActionException{
        QueryVariable qv = getVariable();
        if(!qv.verify())
            throw new EngineException("Invalid queries: either null or empty");
    }  //verify();
 
    public Object execute(FlowContext fc){
        QueryVariable qv = getVariable();
        System.out.println(qv.queries);
        
        try{
            Class.forName("com.mysql.jdbc.Driver").newInstance();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    
        Connection connection = null;
    
        try{
            connection = DriverManager.getConnection("jdbc:mysql://localhost/testdata","root", "test");
        }
        catch(Exception e){
            e.printStackTrace();
        }
    
        Statement s = null;
    
        try{
            s = connection.createStatement();
            Iterator it = qv.queries.iterator();
            while(it.hasNext())
                s.addBatch((String) it.next());
                s.executeBatch();  
        }
        catch(SQLException e){
            e.printStackTrace();
        }
        return true;
    }  //execute
 
    // Methods required by the interface SQLAction
    // These are mostly just call the methods in the data class QueryVariable
 
    public void addQuery(String query){
        QueryVariable qv = getVariable();
        qv.addQuery(query);
        putVariable(qv);
    }  //addQuery()
 
    public void clearQueries(){
        QueryVariable qv = getVariable();
        qv.clearQueries();
        putVariable(qv);
    }  //clearQueries()
 
    public boolean removeQuery(String query){
        QueryVariable qv = getVariable();
        boolean ret = qv.removeQuery(query);
        if(ret)
            putVariable(qv);
        return ret;
    }
 
    public ArrayList<String> getQueries(){
        QueryVariable qv = getVariable();
        return qv.queries;
    }
}   


  • Create a factory for your action that allows you to make instances of your action. This process is detailed in the section "Getting Started: Creating a Factory class" located above. Our example continues with the following factory.
import flux.dev.AdapterFactory;
import fluximpl.FlowChartImpl;
 
public class SQLFactory implements AdapterFactory {
    private FlowChartImpl fc;
 
    public void init(FlowChartImpl fc){
        this.fc = fc;
    }
 
    public SQLAction makeSQLAction(String name){
        return new SQLActionImpl(fc, name);
    }
}  


And the factories.properties file:
sqlfact=SQLFactory  


  • Your custom action is now ready to be used in development. To create an instance of your custom action, you must first create the factory you made by calling the makeFactory(String shortname) method on the flow chart you are working on. From there, call the appropriate make method on the factory object you just made to create an instance of your custom action. From here it is just like any other action; you must set the appropriate action properties, and optionally set flows, variable mapping, or whatever else you need to cement it in place in your flow chart.
Average User Rating
(0 ratings)




There are no comments on this document