Java allows to execute multiple threads concurrently. We can use this approach to enable parallel execution of functions in the JavaScript runtime environment also. This example shows how parallel execution can be easily implemented in JavaScript. In this context it is important to note that parallel threads cannot write anything directly to the standard output stream of VMware Aria Automation, because it cannot be displayed by using the method System.log, if an output is necessary.

Hint: For this approach it is necessary to set the system property com.vmware.scripting.javascript.allow-native-object to true or add in the shutter file the java.* and org.* package, or the relevant subsets of it.

To get the source code move your mouse pointer into the source code section and press on the upper right side the copy button. This copies the source code to the clipboard and now it can be pasted into an action and saved on the target Aria Automation system.

Thread Class with Output Redirecting

First a look at an implementation using the Java Thread class. In this case the standard output stream is to be redirected, as long as a thread is running. In this example this was implemented for reasons of clarity. Once this has happened, the thread can be started asynchronously. In this case the asynchronous function counts every second, for ten seconds. The caller waits four seconds and then it interrupts the thread by using a global control variable. Finally the content of the file, which contains the redirected output stream, are read and displayed.

/**
 * Checked with VMware Aria Automation 8.12.0 and 8.13.1.
 *
 * Hint: This approach is not thread-safe.
 *
 * @author Stefan Schnell <mail@stefan-schnell.de>
 * @license MIT
 * @version 0.1.0
 */

var _interruptAsynchThread = false;

/**
 * Thread to be executed asynchronously
 */
var _asynchThread = java.lang.Thread(function() {

  java.lang.System.out.println("Start asynchronous thread");

  var counter = 0;

  while (_interruptAsynchThread === false) {

    java.lang.System.out.println(counter.toString());

    System.sleep(1000);

    counter++;
    if (counter > 9) {
      _interruptAsynchThread = true;
    }

  }

  java.lang.System.out.println("End asynchronous thread");

});

/**
 * Function which starts and terminates the asynchronous thread
 */
function _startAsynchThread() {

  _asynchThread.start();

  java.lang.System.out.println("Asynchronous thread has been started");
  System.sleep(4000);
  java.lang.System.out.println("Now the asynchronous thread is interrupted");
  _interruptAsynchThread = true;
  java.lang.System.out.println("End function");

  _asynchThread.join();

}

/**
 * It is necessary to redirect the standard output, because the output
 * of the asynchronous thread is not displayed via System.log
 */
function Main() {

  var uuid = System.nextUUID();
  var stdoutFileName = System.appendToPath(
    System.getTempDirectory(), uuid + "_stdout.txt"
  );
  var standardOut = java.lang.System.out;
  java.lang.System.setOut(
    java.io.PrintStream(java.io.FileOutputStream(stdoutFileName))
  );

  _startAsynchThread();

  java.lang.System.setOut(
    java.io.PrintStream(standardOut)
  );

  var stdoutReadFile = new FileReader(stdoutFileName);
  if (stdoutReadFile.exists) {
    stdoutReadFile.open();
    System.log(stdoutReadFile.readAll());
    stdoutReadFile.close();
  }

}

// Main
Main();

The following image shows the result of an execution in Aria Automation.

vmware aria automation with the result from java parallel thread execution

Executor Interface with Logger

The following source code shows another approach, without the redirecting of the standard output stream. VMware Aria Automation uses the Simple Logging Facade for Java (SLF4J). Here a connection to the existing log is established. The Java Executor interface is also used. It is a simple standardized interface for defining custom thread-like subsystems, including thread pools, asynchronous I/O and lightweight task frameworks.

/**
 * Checked with VMware Aria Automation 8.12.0
 *
 * @author Stefan Schnell <mail@stefan-schnell.de>
 * @license MIT
 * @version 0.2.0
 */

var _interruptAsynchThread = false;
var _systemLog = org.slf4j.LoggerFactory.getLogger("SCRIPTING_LOG");
var _contextMap = org.slf4j.MDC.getCopyOfContextMap();

/**
 * Thread to be executed asynchronously
 */
var _asynchThread = java.lang.Thread(function() {

  org.slf4j.MDC.setContextMap(_contextMap);
  _systemLog.info("Asynchronous thread: {}", "Start");

  var counter = 0;
  while (_interruptAsynchThread === false) {
    _systemLog.info("Asynchronous thread: {}", counter);
    System.sleep(1000);
    counter++;
    if (counter > 9) {
      _interruptAsynchThread = true;
    }
  }

  _systemLog.info("Asynchronous thread: {}", "End");

});

/**
 * Function which starts and terminates the asynchronous thread
 */
function Main() {

  var executor = java.util.concurrent.Executors.newFixedThreadPool(2);
  executor.execute(_asynchThread);

  System.log("Asynchronous thread has been started");
  System.sleep(4000);
  System.log("Now the asynchronous thread is interrupted");
  _interruptAsynchThread = true;
  System.log("End function");

  executor.shutdown();
  executor.awaitTermination(5, java.util.concurrent.TimeUnit.SECONDS);

}

// Main
Main();

The following image shows the result of an execution in Aria Automation.

vmware aria automation with the result from java parallel thread execution via executor interface

As can be seen here, the direct SLF logging takes a specific format, the parameterized log message.

Executor Interface with Logger and Parameter Passing

The following source extends the previous. Five threads are started in parallel and an identification number is passed as a parameter to each thread.

/**
 * Checked with VMware Aria Automation 8.12.0 and 8.14.0
 *
 * @author Stefan Schnell <mail@stefan-schnell.de>
 * @license MIT
 * @version 0.3.0
 */

var _interruptAsynchThread = false;
var _systemLog = org.slf4j.LoggerFactory.getLogger("SCRIPTING_LOG");
var _contextMap = org.slf4j.MDC.getCopyOfContextMap();
var _asynchThreads = [];

/**
 * Thread to be executed asynchronously
 */
var _asynchThread = { func : function(threadNumber) {

    org.slf4j.MDC.setContextMap(_contextMap);
    var threadId = java.lang.Thread.currentThread().getId();
    var threadName = java.lang.Thread.currentThread().getName();
    _asynchThreads.push(
      {threadId: threadId, threadName: threadName, threadNumber: threadNumber}
    );
    _systemLog.info("Start asynchronous thread with ID " + threadId +
      ", name " + threadName + " and number " + threadNumber);

    var counter = 0;
    while (_interruptAsynchThread === false) {
      _systemLog.info(" > Counter: " + counter.toString() +
        " from thread number " + threadNumber + " < ");
      System.sleep(1000);
      counter++;
      if (counter > 9) {
        _interruptAsynchThread = true;
      }
    }

    _systemLog.info("End asynchronous thread with ID " + threadId +
      ", name " + threadName + " and number " + threadNumber);

  }
};

/**
 * Function which starts and terminates the asynchronous thread
 */
function Main() {

  var executor = java.util.concurrent.Executors.newFixedThreadPool(5);

  for (var i = 0; i < 5; i++) {
    (function(counter) {
      executor.execute(function() { _asynchThread.func(counter); });
    } )(i);
  }

  System.log("Asynchronous thread has been started");
  System.sleep(4000);
  System.log("Now the asynchronous thread is interrupted");
  _interruptAsynchThread = true;
  System.log("End function");

  executor.shutdown();
  executor.awaitTermination(
    java.lang.Short.MAX_VALUE,
    java.util.concurrent.TimeUnit.SECONDS
  );

}

// Main
Main();

The following image shows the result of an execution in Aria Automation, with 1 second sleep time in the main thread.

vmware aria automation with the result from java parallel thread execution via executor interface



This site is part of blog.stschnell.de