Basic Robotic Process Template

If you're getting started with Appian RPA, use this template of a basic robotic process as a guide to create your own. The robotic process generated by this template can be executed to show the generic behavior of a robotic process, without doing a real processing of the items.

This page includes the steps to build a basic robotic process, along with some explanations. You'll notice comments on aspects related to the workflow and to the source code, showing both methods called directly from the code and implicitly by the platform.

The generated robotic process will treat a fixed number of items through a loop, performing tasks before and after this loop. The treatment is very simple: the only thing to do is to mark the result of each item as an OK or WARN. As already mentioned, this processing is not real, so the items will be identified simply by a string including the number of the iteration involved. Further in this page, we'll explain how the current item is identified.

Depending on the nature of your robotic processes, an item could be: a person, an ID, a bank account, an invoice, a job identifier, etc.

Workflow

basic-robot-workflow.png

This workflow is rather simple to show the actions a well designed robotic process should contain.

The process starts with the Init action and then a proceeds to a Pre-Process action. It then advances to a loop in charge of processing the items. including two actions: More items? and Process Item. When the process detects there are no more items to process, the workflow advances to the Post-Process action. Finally, the process ends with the End action.

The fact that only one action is present before, after, and inside the loop is for simplicity. Many real robotic processes include more than one action in each of these positions in the workflow.

Code

The code generated by this template contains a class named BaseRobot that, as every Appian RPA robotic process, implements IRobot and is annotated with @Robot. This class has attributes and methods we explain below.

Regarding the methods, apart from each of those associated to each action, this template generates three additional methods called by the platform in different moments. If we pay attention to when they would be called, we could have the following order:

  1. startUp()
  2. start()
  3. preProcess()
  4. moreItems()
  5. processItem()
  6. postProcess()
  7. end()
  8. cleanUp()

It is important to note the method manageException(), which can be called at any moment by the platform when an uncaught exception is thrown, either explicitly by our code or implicitly. In our case, we will see that in the action Process Item an exception of type JidokaItemException is thrown, which will cause a call to this method.

Attributes

We see the attributes and the constant generated for this robotic process:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  /**
     * Pause in milliseconds between actions to mimic human behavior.
     */
    private static final int PAUSE = 500;

    /**
     * Object to communicate with the server.
     */
    private IJidokaServer<?> server;
    
    /**
     * Object for performing actions on the node.
     */
    private IClient client;
    
    /**
     * Current item index.
     */
    private int currentItemIndex;
    
    /**
     * Current item that will be set in every iteration of the loop.
     */
    private String currentItem;

    /**
     * Number of items.
     */
    private int numberOfItems;

Besides the definition of a constant for pauses (in milliseconds), PAUSE, we can find references to IJidokaServer and IClient, used to make the robotic process communicate with the server and allow it to perform actions on the resource, respectively.

To keep track of what item is being processed at any moment, the following attributes exist:

  • currentItemIndex: it stores a 0-based index to control how many item have been processed so far.

Remember that although the Java attribute is 0-based, the notification to the server must be done as a 1-based number, that is, for the first item, we have to send a 1 and not a 0.

  • currentItem: it stores the current item (represented by a string).
  • numberOfItems: it stores the total number of items.

startUp method

This method is called by the platform prior to the execution of the actions of the workflow. For more information you can visit the section about the method startUp().

In the case of this template, the generated code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  @Override
    public boolean startUp() {
        
        // Initialize modules
        server = JidokaFactory.getServer();
        client = IClient.getInstance(this);
        
        /*
         * TODO: Here you can check any condition that could make the robotic process not work
         * properly. In this case, you want to return 'false' so the robotic process doesn't
         * continue the execution.
         */
        
        // If there weren't any problems, the robotic process can continue
        return true;
    }

As we can see, we are using it to initialize the instances to the interfaces IServer and IClient. In addition, a comment indicates a possible application, such us checking any condition preventing the robotic process work properly, in which case we should return false. Only when true is returned, the robotic process will start executing the actions defined in its workflow.

If this method is not implemented by the robotic process (annotation @Override), the platform will call to the default implementation present in the interface IRobot.

start method

This method is associated with the initial action in the workflow (Init).

The generated code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  /**
     * Initial action to execute by the robot.
     * 
     * Associated with the action in the workflow.
     */
    public void start() {
        
        server.debug("Robot initialized!");
        
        /*
         * Set the standard pause after typing or using the mouse. This is not
         * mandatory, but it is very usual.
         */
        client.typingPause(PAUSE);
        client.mousePause(PAUSE);
        
        /*
         * Get the number of items and save it. In this case, we're generating
         * 10 items.
         */
        numberOfItems = 10;
        
        /*
         * TODO: If the number of items are known at this point, this is a good place to
         * notify the server. Anyway, this number must be notified as soon as it is
         * known.
         */
        server.info("Generating items...");
        
        server.setNumberOfItems(numberOfItems);
    }

Here, the first thing done is to send a message of type debug to inform about the correct initialization of the robotic process. Then, the default pauses to make after typing and after using the mouse are defined.

The number of items to process is also set, which must be done as soon as its number is known. This is important for the platform to correctly calculate the statistics and time consumed. In this case, the items are 10.

If in our robotic processes we don't know the exact number of items at the beginning, we can make as many calls to server as needed. The most important is to notify the correct number of items when this data is known.

preProcess method

This method is associated to the action of workflow Pre-Process. Here is where the required steps before processing the items should be coded. The most common examples usually are: open the applications to automate and do the necessary logins.

In our case, the code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /**
     * Method for performing previous tasks before processing the items.
     * 
     * Associated with the action in the workflow.
     */
    public void preProcess() {
        
        server.info("Method for performing previous tasks before processing the items");
        
        /*
         * TODO: Here you can open applications or log in to the systems required for the
         * automation.
         */
    }

The only thing done here is to send a message of type info to the console.

Additionally, a comment has been generated indicating an example of what could be done in this method.

moreItems method

This is a basic method to implement our workflow-guided loop.

The code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /**
     * Evaluates if there are items left to process.
     * 
     * Associated with the action in the workflow.
     * 
     * @return String value of the workflow wire name of the path to take
     */
    public String moreItems() {
        
        // If the index is lower than the number of items, there are items left to process
        if (currentItemIndex < numberOfItems) {
            
            // Increase the item
            currentItemIndex++;
            
            // Assign the new item to process
            currentItem = "itemKey_" + currentItemIndex;
            
            // Notify the server the new current item
            server.setCurrentItem(currentItemIndex, currentItem);
            
            return "yes";
        }
        
        return "no";
    }

This is a condition action. Conditional actions differ from the generic ones because the can return String or boolean. This way, when a method is to be assigned from the workflow, only the methods matching these signatures are selectable.

When the method returns a boolean, there will only be two possible outputs for the conditional action, which must be labeled with the literals "true" and "false." However, when the method returns a String, there can be two or more outputs, which must be labeled with the same literal returned by the method. This latter case corresponds to the conditional action More items?, that has two outputs labeled as "yes" and "no."

What the method really does is check if there are any items left to process. If there are none, it returns the literal "no," while when there are more items to process, it returns the literal "yes".

When there are items left to process, the server is notified what the current one is by calling the method server.setCurrentItem(). To communicate to the server what is the item to process, it is required to specify two parameters: (1) the 1-based item index inside the total number of items to process and (2) the identification of the item. In this case, the item is identified as the concatenation of the literal "itemKey_" and the index of the current iteration. This way, the items will be identified as "itemKey_1", "itemKey_2", "itemKey_3" and so on.

processItem method

This is the other method, beside moreItems(), that forms the workflow-guided loop. It processes each item.

The code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /**
     * In this method, each item is processed at a time.
     * 
     * Associated with the action in the workflow.
     * 
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public void processItem() throws Exception {
        
        /*
         * Provoke an exception for the third item to show how exception handling works.
         * This exception will be caught in the manageException method
         */
        if (currentItemIndex == 3) {
            throw new JidokaItemException((IJidokaServer<Serializable>) server,
                    "Exception thrown for the 3rd item");
        }
        
        // Set the result for the current item
        setCurrentItemResult();
    }

During processing, several different cases can occur. To see them, we are going to show the three different results an item can have:

  1. An exception is thrown.
  2. The result is OK.
  3. The result is WARN.

In the code above, we can see that an exception is explicitly thrown for the third item, which type is JidokaItemException. Later, we'll see how this item is marked as a warning in the method manageException(). We want to show this way of marking a warning as opposed to the usual way.

To see how an item is marked as OK or as WARN, let's see the code of the method setCurrentItemResult():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /**
     * Set the current item to OK or WARN with a probability of 50%.
     */
    private void setCurrentItemResult() {
        
        // Calculate a random integer between 0 and 1
        Random rd = new Random();
        int n = rd.nextInt(2);
        
        if (n == 0) {
            
            // The current item will be WARN when the random number is equal to 0
            server.setCurrentItemResultToWarn("Warning randomly calculated!");
        } else {
            
            // The current item will be OK when the random number is equal to 1
            server.setCurrentItemResultToOK("OK randomly calculated!");
        }
        
    }

Basically, what we're doing here is the item processing, which consists of deciding, randomly, if the current item will be OK or WARN, with a 50% chance for each option.

To send the result to the server, in the code we can see the following two calls to server to the methods:

  • setCurrentItemResultToWarn(): it sets the current item result to WARN, passing as a parameter a descriptive text.
  • setCurrentItemResultToOK(): it sets the current item result to OK, passing as a parameter a descriptive text.

These calls cause the execution statistics to appear in the console, indicating, among other information, the result of the item with its description and the corresponding color (yellow for WARN and green for OK).

postProcess method

This method is associated to the action Post-Process of the workflow. The tasks we considered necessary after the items processing can be done here. Following the example of the method preProcess, we could: close the applications being automated and perform the required logouts.

The code generated for this method is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /**
     * Method for performing tasks after the items have been processed.
     * 
     * Associated with the action in the workflow.
     */
    public void postProcess() {
        
        server.info("Method for performing tasks after the items have been processed");
        
        /*
         * TODO: Here you can close the applications or log out the systems opened
         * before the items processing.
         */
    }

First, the server is notified with message of type info.

As in previous methods, an informative comment is present indicating what could be done in this method.

end method

This method is associated to the final action of the workflow (End). In this method the final steps we think our robotic process must do should be coded.

The code generated by this template is as follows:

1
2
3
4
5
6
7
8
  /**
     * Final action to execute by the robot.
     * 
     * Associated with the action in the workflow.
     */
    public void end() {
        server.debug("Robot finished!");
    }

The only thing the robotic process does here is to send a message of type debug to indicate the robotic process has finished.

cleanUp method

As in the case of the method startUp, this method is called by the platform. This is done when all the actions of the workflow have finished their execution, or if any situation causes the robotic process to end abruptly. For more information you can visit the section about the method cleanUp().

The method cleanUp() has two main goals:

  1. Leave the resource in the same state than before the robotic process started its execution. Since the platform assures this call is done regardless of the reason of the execution end, this is the right place to perform all the "clean" tasks required on the resource. These could be: closing the applications, killing the processes that may have been left open, logging out of the systems involved, etc. Previously, in the method postProcess(), we also mentioned that this kind of tasks could be done, so it can be a good idea to encapsulate these tasks in private methods and call them from both cleanUp() and postProcess() methods.
  2. Return output files that can be downloaded directly from the robotic process execution page. To send files to the server, this method must return an array of Strings referring to the local paths of the generated files.

In the case of this template, the generated code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  @Override
    public String[] cleanUp() throws Exception {
        
        /*
         * TODO: since this method is called when the execution ends, no matter if it
         * ended well or not, here you should assure the node is left in the same state
         * it was before the execution started. For instance, by closing applications or
         * logging out.
         */
        
        server.info("Cleaning up...");
        
        /*
         * TODO: If the execution must return any file, it has to be done here. To do so
         * you have to return the paths to each file as a String array.
         */
        
        return new String[0];
    }

In the code above, these two main goals are explained in comments. Because this robotic process doesn't return any file, an empty array of Strings is returned, although it could have been valid to return null too.

If this method is not implemented by the robotic process (annotation @Override), the platform will call the default implementation present in the interface IRobot.

manageException method

This is the third of the methods called by the platform implicitly. It is called whenever an exception is thrown during the execution and it is not explicitly caught in the rest of the code. For more information you can visit the section about the method manageException().

The generated code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  @Override
    public String manageException(String action, Exception exception) throws Exception {
        
        // Optionally, we send the exception to the execution log
        server.warn(exception.getMessage(), exception);
        
        /*
         * We take advantage of the Apache Commons ExceptionUtils class to know if a
         * specific exception was thrown throughout the code.
         * Since we threw a JidokaItemException, it's the one to be searched in the
         * exceptions stack trace. If found, the flow goes to the next item by telling
         * the next method to execute is 'moreItems()'.
         * If another exception is found, it is propagated, so the robot ends with a
         * failure.
         */
        if (ExceptionUtils.indexOfThrowable(exception, JidokaItemException.class) >= 0) {
            server.setCurrentItemResultToWarn("Exception processing the item!");
            return "moreItems";
        }
        
        // Unknown exception. Throw it
        throw exception;
    }

This method is called by the platform. The parameters are filled with information about the action in which the exception was thrown, as well as the exception itself.

The second parameter, exception, containing the exception, actually contains the chain of exceptions generated. To find a specific exception, we have to search it.

In this method, the first thing done is to send a warning to the log with the message of the exception, as well as the stack trace, that will appear in the execution page.

It then uses a third-party dependency, in this case Apache Commons, which contains a utility class called ExceptionUtils. We make use of it to know if the chain of exceptions received by parameter contains the exception JidokaItemException, which we must remember it is thrown previously in the method processitem() for the third item.

As we saw previously for methods startUp() and cleanUp(), if this method is not implemented by the robotic process (annotation @Override), the platform will call to the default implementation present in the interface IRobot.

Open in Github

On This Page

FEEDBACK