Context Robot Tutorial

In this tutorial, we are going to implement a robot whose main goal is to show how to work properly with the context across executions of the same robot.

The context class allows storing persistent information across executions. The use of this functionality permits a new robot execution to know about the final conditions of the previous one, which makes it easier to implement reentrant robots, that is, those capable to resume a process from the last item in which the previous execution stopped.

However, to illustrate this example we have used in another way, showing how to read, update or reset the context. Specifically, this robot is in charge of checking the web driver versions used to connect Selenium with the browsers supported by Appian RPA Browser module, which are Chrome, Internet Explorer and Firefox. In case that a new version is found in the download pages, the execution will finish with a warning for the corresponding browser. For this reason, the items to process here will be the browsers. A possible use of this robot would be the creation of an alert when this happens, making it possible to notify that a new driver has been released for a specific browser.

Source Code and Support Files

Description Link
Source Code robot-tutorial-context.zip
Chrome Driver v2.35 chromedriver.exe

Review Browser module architecture page for other browser versions.

Configuration

Environment

  • Development:
    • IDE: Eclipse
    • JDK 1.8
    • Maven 3
    • Appian RPA modules:
      • Client
  • Resource:
    • OS: Windows
    • JRE 1.8
    • Applications:
      • Firefox, Chrome or IE11 browser

Eclipse Project

You must import the Eclipse project included in the zip file attached at the beginning of this tutorial. After importing the project, it is very important to modify the pom.xml file. You have to fill in the parent tag with the version of Appian RPA you are using, and change the profile tag with the configuration of your repository.

Workflow

The robot will navigate to each web driver download page and check the last released version for each one.

Once this information is extracted, it will retrieve the last version of each browser stored in the Appian RPA server context and will compare it with each of the just found on the pages. Depending on this comparison, it will set an OK for the browsers (items) which version has not changed, whilst a warning will be set for those browsers for which a new version exists.

rpa-context-workflow.png

You can import this workflow using this file. To import the workflow, you have to click in the import button (2233684.png), and paste the data included in the file.

Support Files

This robot will use Chrome, thus needing its driver, chromeWebDriver, as a support file to work. It could also be added as a global support file instead.

2230664.png

Implementation

Before going on, we should know that the context is only read once at the beginning of an execution. This way, any change made on it will not be reflected until the next execution.

In this implementation, we have created a context class, called DriverContext, that is the type of the object to use for keeping the data persisted in the Appian RPA server. This class contains only three variables of type String with the driver version as their corresponding values.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * Class to store the context across robot executions.
 */
public class DriverContext implements Serializable  {

    /**
     * Serial.
     */
    private static final long serialVersionUID = 1L;
    
    /**
     * Default value when the context is created by the first time or it is
     * reset.
     */
    private static final String DEFAULT_VALUE_EMPTY = "empty";
    
    /**
     * Variable to store Chrome driver version into the context.
     */
    private String lastChromeDriverVersion;
    
    /**
     * Variable to store IE Driver version into the context.
     */
    private String lastIEDriverVersion;
    
    /**
     * Variable to store Firefox driver version into the context.
     */
    private String lastFirefoxDriverVersion;
    
    /**
     * Initialization to the default value.
     */
    public DriverContext() {
        lastChromeDriverVersion = DEFAULT_VALUE_EMPTY;
        lastIEDriverVersion = DEFAULT_VALUE_EMPTY;
        lastFirefoxDriverVersion = DEFAULT_VALUE_EMPTY;
    }
    
    public String getLastChromeDriverVersion() {
        return lastChromeDriverVersion;
    }
    
    public void setLastChromeDriverVersion(String lastChromeDriverVersion) {
        this.lastChromeDriverVersion = lastChromeDriverVersion;
    }
    
    public String getLastIEDriverVersion() {
        return lastIEDriverVersion;
    }
    
    public void setLastIEDriverVersion(String lastIEDriverVersion) {
        this.lastIEDriverVersion = lastIEDriverVersion;
    }
    
    public String getLastFirefoxDriverVersion() {
        return lastFirefoxDriverVersion;
    }
    
    public void setLastFirefoxDriverVersion(String lastFirefoxDriverVersion) {
        this.lastFirefoxDriverVersion = lastFirefoxDriverVersion;
    }
}

Looking at the robot variables definition, we want to stop at the declaration of an object of type IJidokaServer, that we will use to indicate the context class to use by the robot: DriverContext.

1
2
3
4
/**
 * Server.
 */
private IJidokaServer<DriverContext> server;

The three first methods navigate to the different pages to look for the last version of each driver, they extract them to store them in the corresponding attributes and write in the execution log the found version. These methods call other private methods in charge of doing these tasks: checkDriver, extractDriverVersion and infoDriver.

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * Checks the Chrome web driver version.
 */
public void checkChrome() {
    
    WebElement we = checkDriver(URL_CHROME,
            XPATH_CHROME_DRIVER);
    
    currentChromeDriverVersion = extractDriverVersion(we, REGEX_CHROME);
    
    infoDriver(currentChromeDriverVersion);
}
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * Checks the Internet Explorer web driver version.
 */
public void checkIE() {
    
    WebElement we = checkDriver(URL_IE,
            XPATH_IE_DRIVER);
    
    currentIEDriverVersion = extractDriverVersion(we, REGEX_IE);
    
    infoDriver(currentIEDriverVersion);
}
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * Checks the Firefox web driver version.
 */
public void checkFirefox() {
    
    WebElement we = checkDriver(URL_FIREFOX,
            XPATH_FIREFOX_DRIVER);
    
    currentFirefoxDriverVersion = extractDriverVersion(we, null);
    
    infoDriver(currentFirefoxDriverVersion);
}

The three first methods navigate to the different pages to look for the last version of each driver, they extract them to store them in the corresponding attributes and write in the execution log the found version. These methods call other private methods in charge of doing these tasks: checkDriver, extractDriverVersion and infoDriver.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * Checks the URL passed by parameter, access it and evaluates the XPath
 * expression specified to get an HTML containing the information of the web
 * driver.
 * 
 * @param url
 *            URL to access to
 * @param xpathExpression
 *            expression to evaluate
 * @return the containing the driver information to be
 *         processed later
 */
private WebElement checkDriver(String url, String xpathExpression) {

    // Navigate to the driver page
    browser.navigate(url);

    // WebElement containing the driver version
    return browser.getElement(By.xpath(xpathExpression));
}

The checkDriver method navigates to the URL passed as a parameter and evaluates the XPath expression, also passed as a parameter, to get an object of type WebElement containing information about the web driver version. This object will be used later by the method extractDriverVersion to extract the web driver version. The XPath expressions to obtain each WebElement are defined as constants in the class.

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
32
33
/**
 * Extracts the web driver version contained in the
 * specified. If a regular expression is specified, it is applied to get the
 * web driver version.
 * 
 * @param we
 *            the with the web driver information
 * @param regex
 *            the regular expression to evaluate
 * @return the extracted version
 */
private String extractDriverVersion(WebElement we, String regex) {
    
    // If no regular expression is present, return
    if (regex == null) {
        return we.getText();
    }
    
    // A regular expression must be evaluated
    server.info(String.format(
            "Serching web driver using the regular expression %s", regex));
    // Search with regular expression
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(we.getText()); 
    if (m.find()) {
        // The version extracted from the method parameter 'we'
        return m.group();
    }
    
    // Nothing found using the regular expression
    throw new JidokaFatalException(String.format(
            "Web driver not found using the regex %s", regex));
}

The private method extractDriverVersion will use the WebElement object returned by checkDriver to extract the specific version of each browser. If it is not necessary to treat the text contained in parameter we, it will be returned directly using getText(). In other case, it will evaluate the specified regular expression on that text to find the web driver version. The regular expressions used are defined as constants in the class.

1
2
3
4
5
6
7
8
9
10
11
/**
 * Print an INFO message to the execution log to show the driver version.
 * 
 * @param driverVersion
 *            the driver version
 */
private void infoDriver(String driverVersion) {

    server.info(String.format(
            "The current web driver version is %s", driverVersion));
}

The last one of this set of private methods is infoDriver, which will use the extracted text of the web driver version to write in the execution log.

Below, we are going to see the method used to retrieve the versions previously stored in the context and compare them with those obtained in the current execution: compareDriversVersions. This way, it is possible to check if any change has been made in any version of the drivers, thus establishing its new value in the context.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
 * Action 'Compare Versions with Context'.
 * 
 * Checks all drivers versions and compares them to those saved previously
 * in the context.
 *
public void compareDriversVersions() {
    
    //Get the context
    DriverContext driverContext = server.getPersistentContextValue();

    if (driverContext == null) {
        server.info("The context does not exist. It was reset or this is is the first time the robot is executed");
        driverContext = new DriverContext();
    } else {
        
        server.info("Context retrieved successfully");
        
        server.info(String.format("IEDriverVersion %s",
                driverContext.getLastIEDriverVersion()));
        server.info(String.format("ChromeDriverVersion %s",
                driverContext.getLastChromeDriverVersion()));
        server.info(String.format("FirefoxDriverVersion %s",
                driverContext.getLastFirefoxDriverVersion()));
    }
    
    // IE
    server.setCurrentItem(1, "Internet Explorer");
    compareVersion(driverContext.getLastIEDriverVersion(),
            currentIEDriverVersion);
    driverContext.setLastIEDriverVersion(currentIEDriverVersion);

    // Chrome
    server.setCurrentItem(2, "Chrome");
    compareVersion(driverContext.getLastChromeDriverVersion(),
            currentChromeDriverVersion);
    driverContext.setLastChromeDriverVersion(currentChromeDriverVersion);
    
    // Firefox
    server.setCurrentItem(3, "Firefox");
    compareVersion(driverContext.getLastFirefoxDriverVersion(),
            currentFirefoxDriverVersion);
    driverContext.setLastFirefoxDriverVersion(currentFirefoxDriverVersion);
    
    // Set the context
    server.setPersistentContextValue(driverContext);
}

This method delegates in the private method compareVersion to actually make the comparison between the just obtained version and the one stored in previous executions. To do so, it calls this method once per each browser.

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
/**
 * Method to compare the value obtained from the driver web to the values
 * retrieved from the context.
 * 
 * 
 * If there is some differences, the item will be set to WARN.
 * If there is not any difference, the item will be set to OK.
 *  
 *
 * @param previousVersion
 *            version stored in the context
 * @param currentVersion
 *            version obtained from the web
 */
private void compareVersion(String previousVersion, String currentVersion) {
    
    if (currentVersion.equals(previousVersion)) {

        server.info(String.format(
                "The web driver has not changed: '%s'", currentVersion));
        server.setCurrentItemResultToOK(currentVersion);
    } else {
        
        String wrnMsg = String.format(
                "The web driver has changed. Previous version was '%s', New version is %s'",
                previousVersion, currentVersion);
        server.info(wrnMsg);
        server.setCurrentItemResultToWarn(wrnMsg);
    }
}

Finally, in the method end, apart from closing the browser, the context is reset in case that it is specified as an input variable in the robot.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * Action 'End'.
 * 
 * Resets the context in case the robot execution indicates so.
 */
public void end() {
    
    Map<String, String> parameters = server.getWorkflowParameters();
    
    boolean reset = Boolean.parseBoolean(
            parameters.get(RESET_CONTEXT_PARAM));
    
    if (reset) {
        server.resetPersistenContextValue();
        
        server.info("The context was reset");
    }
    
    // Close the browser
    browser.close();
}

Execution

Once the robot is implemented, it will be deployed to the Appian RPA repository.

mvn clean deploy

Optionally, when the robot is going to be launched, it is possible to specify an additional input variable of type boolean to try to reset the context at the end of the execution. This is done to help to understand how this functionality works.

rpa-context-exec-options.png

Below, it is shown the log trace of the first execution of this robot or when the context was reset in a previous execution, that is, when the context is not set.

2230680.png

Once the context has been set, and assuming that the extracted versions don't change, this would be the result:

2230681.png

In subsequent executions, the result will be like the last one until some of the driver versions change.


This version of the Appian RPA documentation was written for Appian 21.4, and does not represent the interfaces or functionality of other Appian versions.
Open in Github Built: Tue, Nov 23, 2021 (07:31:45 PM)

On This Page

FEEDBACK