Manually Refreshing the Runtime Configuration from a File

Flux provides a built-in mechanism for loading and automatically refreshing the runtime configuration by using (using the RUNTIME_CONFIGURATION_FILE and RUNTIME_CONFIGURATION_FILE_REFRESH_FREQUENCY configuration options). In some cases, however, you will want more control over exactly when and how the file is refreshed.

This example demonstrates how you can load, parse, and set the runtime configuration yourself, bypassing the automated process on the engine.

Example Code

import flux.*;
import flux.runtimeconfiguration.RuntimeConfigurationNode;

import java.util.Properties;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.List;
import java.io.FileInputStream;

/**
 * Example code demonstrating how to manually load and refresh the runtime configuration from a file without using
 * Flux's automatic refresh.
 */
public class RuntimeConfigurationManualRefresh {
    public static Factory factory = Factory.makeInstance();

    //    Update this to point to your own runtime configuration file.
    public static String runtimeFileLocation = "/path/to/runtime.config";
    public RuntimeConfigurationManualRefresh() throws Exception {

//    First, make a Flux engine
        Engine engine = factory.makeEngine();

//    Now set the runtime configuration on the engine.
        engine.setRuntimeConfiguration(reloadRuntimeConfiguration());

//    Make a flow chart that uses the runtime variable. The example code below assumes you have a runtime variable
//    in the configuration file called "MY_RUNTIME_VARIABLE" - you can change this to use one of your own variables
//    if you prefer.
        FlowChart flowChart = EngineHelper.makeFlowChart("My Flow Chart");
        ConsoleAction consoleAction = flowChart.makeConsoleAction("My Console Action");

//    Use runtime variable substitution to print the value of the variable.
        consoleAction.setMessage("${runtime MY_RUNTIME_VARIABLE}\n");

//    Start the engine and add the flow chart.
        engine.start();
        engine.put(flowChart);

//    Wait for the flow chart to finish running.
        engine.join("/My Flow Chart", "+1m", "+5s");

//    Instruct the user that they should now update the runtime configuration. This will allow the user to see that
//    the runtime configuration is actually reloaded.
        System.out.println("Flow chart complete. " +
                "Change the value of the runtime configuration variable MY_RUNTIME_VARIABLE in the file now.");

//    Sleep for 30 seconds to allow time to update the runtime configuration.
        Thread.sleep(30000);

//    Update the runtime configuration again - this will pull the new value for MY_RUNTIME_VARIABLE.
        engine.setRuntimeConfiguration(reloadRuntimeConfiguration());

//    Now re-export the flow chart so the new value will be printed.
        engine.put(flowChart);

//    Wait for the flow chart to finish running.
        engine.join("/My Flow Chart", "+1m", "+5s");
        System.out.println("This example is complete! Now you can see how the runtime configuration is manually reloaded.");
    }

    public static RuntimeConfigurationNode reloadRuntimeConfiguration() throws Exception {

//    Load the runtime configuration from a file.
        Properties properties = new Properties();
        properties.load(new FileInputStream(runtimeFileLocation));

//    Parse the runtime configuration.
        RuntimeConfigurationNode root = factory.makeRuntimeConfigurationFactory().makeRuntimeConfiguration();
        RuntimeConfigurationNode currentNode = root;
        Enumeration names = properties.propertyNames();
        while (names.hasMoreElements()) {
            String branch = (String) names.nextElement();

//      Break the branch up into namespaces.
            StringTokenizer st = new StringTokenizer(branch, "/");
            currentNode = root;
            for (int i = st.countTokens(); i > 0; i--) {
                String name = (String) st.nextElement();

//        If there are more elements, that means we are not at the end of the branch yet, so we need to travel down to
//        the next namespace level.
                if (i > 1) {
                    RuntimeConfigurationNode node = currentNode.getChild(name);

//          If the namespace doesn't already exist in the runtime configuration, create it and set it as the current
//          node.
                    if (node == null) {
                        currentNode = currentNode.makeChild(name);
                    } else {

//            Otherwise just set the current node to this namespace.
                        currentNode = node;
                    }
                } else {

//          We are now at the end of this branch so we can set the value.
                    String value = properties.getProperty(branch, "");
                    if (name.equalsIgnoreCase(RuntimeConfigurationNode.DEFAULT_FLOW_CHART_ERROR_HANDLER)) {

//            Load the error handler flow chart.
                        currentNode.setDefaultFlowChartErrorHandler(loadFlowChart(value));
                    } else if (name.equalsIgnoreCase(RuntimeConfigurationNode.CONCURRENCY_THROTTLE)) {
                        currentNode.setConcurrencyThrottle(value);
                    } else if (name.equalsIgnoreCase(RuntimeConfigurationNode.CONCURRENCY_THROTTLE_CLUSTER_WIDE)) {
                        currentNode.setConcurrencyThrottleClusterWide(value);
                    } else if (name.equalsIgnoreCase(RuntimeConfigurationNode.FIFO_SCHEDULING_ENABLED)) {
                        currentNode.setFifoSchedulingEnabled(new Boolean(value));
                    } else if (name.equalsIgnoreCase(RuntimeConfigurationNode.INTERNAL_LOGGER_DEBUG_ENABLED)) {
                        currentNode.setInternalLoggerDebugEnabled(new Boolean(value));
                    } else if (name.equalsIgnoreCase(RuntimeConfigurationNode.LISTENER_CLASSPATH)) {
                        currentNode.setListenerClasspath(value);
                    } else if (name.equalsIgnoreCase(RuntimeConfigurationNode.PRIORITY)) {
                        currentNode.setPriority(new Integer(value));
                    } else if (name.equalsIgnoreCase(RuntimeConfigurationNode.RUN_AS_USER)) {
                        currentNode.setRunAsUser(value);
                    } else {
                        currentNode.put(name, value);
                    }
                }
            }
        }

//    If there wasn't an error handler or listener class path specifies, use the built-in ones.
        RuntimeConfigurationNode defaultRuntime = factory.makeRuntimeConfigurationFactory().makeDefaultRuntimeConfiguration();
        if (root.getDefaultFlowChartErrorHandler() == null) {
            root.setDefaultFlowChartErrorHandler(defaultRuntime.getDefaultFlowChartErrorHandler());
        }
        if (root.getListenerClasspath() == null) {
            root.setListenerClasspath(defaultRuntime.getListenerClasspath());
        }
        return root;
    }

    public static FlowChart loadFlowChart(String urlPath) throws Exception {
        List flowCharts = EngineHelper.makeFlowChartsFromXml(new FileInputStream(urlPath), false);

//    If there are more than one flow charts in the file, just return the first one.
        if (flowCharts.size() > 0) {
            return (FlowChart) flowCharts.get(0);
        } else {
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        new RuntimeConfigurationManualRefresh();
    }
}