I want to take base64 screenshot for all the passed and failed screenshots with testNG, below is my code.
private static ExtentReports extent;
private static Platform platform;
private static String reportFileName = "ExtentReports-Version3-Test-Automaton-Report.html";
private static String macPath = System.getProperty("user.dir")+ "/TestReport";
private static String windowsPath = System.getProperty("user.dir")+ "\TestReport";
private static String macReportFileLoc = macPath + "/" + reportFileName;
private static String winReportFileLoc = windowsPath + "\" + reportFileName;
public static ExtentReports getInstance() {
if (extent == null)
createInstance();
return extent;
}
//Create an extent report instance
public static ExtentReports createInstance() {
platform = getCurrentPlatform();
String fileName = getReportFileLocation(platform);
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(fileName);
htmlReporter.config().setTestViewChartLocation(ChartLocation.BOTTOM);
htmlReporter.config().setChartVisibilityOnOpen(true);
htmlReporter.config().setTheme(Theme.STANDARD);
htmlReporter.config().setDocumentTitle(fileName);
htmlReporter.config().setEncoding("utf-8");
htmlReporter.config().setReportName(fileName);
extent = new ExtentReports();
extent.setSystemInfo("Author", "Gladson Antony");
extent.setSystemInfo("Browser", Browser);
extent.setSystemInfo("OS", OSName);
extent.setSystemInfo("OS Version", OSVersion);
extent.setSystemInfo("OS Architecture", OSArchitecture);
extent.setSystemInfo("OS Bit", OSBit);
extent.setSystemInfo("JAVA Version",System.getProperty("java.version"));
extent.attachReporter(htmlReporter);
return extent;
}
//Select the extent report file location based on platform
private static String getReportFileLocation (Platform platform) {
String reportFileLocation = null;
switch (platform) {
case MAC:
reportFileLocation = macReportFileLoc;
createReportPath(macPath);
System.out.println("ExtentReport Path for MAC: " + macPath + "\n");
break;
case WINDOWS:
reportFileLocation = winReportFileLoc;
createReportPath(windowsPath);
System.out.println("ExtentReport Path for WINDOWS: " + windowsPath + "\n");
break;
default:
System.out.println("ExtentReport path has not been set! There is a problem!\n");
break;
}
return reportFileLocation;
}
//Create the report path if it does not exist
private static void createReportPath (String path) {
File testDirectory = new File(path);
if (!testDirectory.exists()) {
if (testDirectory.mkdir()) {
System.out.println("Directory: " + path + " is created!" );
} else {
System.out.println("Failed to create directory: " + path);
}
} else {
System.out.println("Directory already exists: " + path);
}
}
//Get current platform
private static Platform getCurrentPlatform () {
if (platform == null) {
String operSys = System.getProperty("os.name").toLowerCase();
if (operSys.contains("win")) {
platform = Platform.WINDOWS;
} else if (operSys.contains("nix") || operSys.contains("nux")
|| operSys.contains("aix")) {
platform = Platform.LINUX;
} else if (operSys.contains("mac")) {
platform = Platform.MAC;
}
}
return platform;
}
Below is my listerner class where I take screenshot for each passed test case using Base64 format.
private static ExtentReports extent = ExtentManager.createInstance();
private static ThreadLocal test = new ThreadLocal();
public synchronized void onStart(ITestContext context) {
System.out.println("Test Suite started!");
}
public synchronized void onFinish(ITestContext context) {
System.out.println(("Test Suite is ending!"));
extent.flush();
}
public synchronized void onTestStart(ITestResult result) {
System.out.println((result.getMethod().getMethodName() + " started!"));
ExtentTest extentTest = extent.createTest(result.getMethod().getMethodName(),
result.getMethod().getDescription());
test.set(extentTest);
}
public synchronized void onTestSuccess(ITestResult result) {
System.out.println((result.getMethod().getMethodName() + " passed!"));
test.get().pass("Test passed");
try {
test.get().pass(result.getTestClass().getName() + "." + result.getMethod().getMethodName(),
MediaEntityBuilder.createScreenCaptureFromBase64String(TestBase.addScreenshot()).build());
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void onTestFailure(ITestResult result) {
System.out.println((result.getMethod().getMethodName() + " failed!"));
test.get().fail(result.getThrowable());
try {
test.get().fail(result.getTestClass().getName() + "." + result.getMethod().getMethodName(),
MediaEntityBuilder.createScreenCaptureFromBase64String(TestBase.addScreenshot()).build());
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void onTestSkipped(ITestResult result) {
System.out.println((result.getMethod().getMethodName() + " skipped!"));
test.get().skip(result.getThrowable());
}
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
System.out.println(("onTestFailedButWithinSuccessPercentage for " + result.getMethod().getMethodName()));
}
Thanks in advance for the favour!!
Related
I have created Hybrid Framework with POM approach, and now i must create Runnable JAR from Selenium that client will be able to execute from its machine. I created TestRunner:
package gov.gao.qa.testcases;
import org.testng.TestNG;
import gov.gao.qa.listeners.ExtentReportListener;
public class TestRunner {
static TestNG testNG;
public static void main(String[] args) {
ExtentReportListener ext = new ExtentReportListener();
testNG = new TestNG();
testNG.setTestClasses(new Class[] {NewBluePTest.class});
testNG.addListener(ext);
testNG.run();
}
}
This is my Report.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="New Blue Publishing Regression Suite" verbose="2" thread-count="2" parallel="tests">
<listeners>
<listener
class-name="gov.gao.qa.listeners.ExtentReportListener" />
</listeners>
<test name="NBP Regression Test_chrome">
<parameter name="browser" value="chrome" />
<classes>
<class name="gov.gao.qa.testcases.NewBluePTest" />
</classes>
</test>
<test name="NBP Regression Test_firefox">
<parameter name="browser" value="firefox" />
<classes>
<class name="gov.gao.qa.testcases.NewBluePTest" />
</classes>
</test>
</suite>
***Extent Report Listener class:***
public class ExtentReportListener extends BasePage implements ITestListener {
private static final String OUTPUT_FOLDER = "./REPOSRTS/";
private static final String FILE_NAME = "TestExecutionReport.html";
private static ExtentReports extent = init();
public static ThreadLocal<ExtentTest> test = new ThreadLocal<ExtentTest>();
private static ExtentReports init() {
Path path = Paths.get(OUTPUT_FOLDER);
if (!Files.exists(path)) {
try {
Files.createDirectories(path);
} catch (IOException e) {
e.printStackTrace();
}
}
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
htmlReporter.config().setDocumentTitle("New Blue Publishing Automation Test Results");
htmlReporter.config().setReportName("Automation Test Results");
htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
htmlReporter.config().setTheme(Theme.STANDARD);
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
extent.setReportUsesManualConfiguration(true);
return extent;
}
public synchronized void onStart(ITestContext context) {
System.out.println("Test Suite started!");
}
public synchronized void onFinish(ITestContext context) {
System.out.println(("Test Suite is ending!"));
extent.flush();
test.remove();
}
public synchronized void onTestStart(ITestResult result) {
String methodName = result.getMethod().getMethodName();
String qualifiedName = result.getMethod().getQualifiedName();
int last = qualifiedName.lastIndexOf(".");
int mid = qualifiedName.substring(0, last).lastIndexOf(".");
String className = qualifiedName.substring(mid + 1, last);
System.out.println(methodName + " started!");
ExtentTest extentTest = extent.createTest(result.getMethod().getMethodName(),
result.getMethod().getDescription());
extentTest.assignCategory(result.getTestContext().getSuite().getName());
extentTest.assignCategory(className);
test.set(extentTest);
test.get().getModel().setStartTime(getTime(result.getStartMillis()));
}
public synchronized void onTestSuccess(ITestResult result) {
System.out.println((result.getMethod().getMethodName() + " passed!"));
test.get().pass("Test passed");
test.get().getModel().setEndTime(getTime(result.getEndMillis()));
}
******FAILES******
public synchronized void onTestFailure(ITestResult result) {
System.out.println((result.getMethod().getMethodName() + " failed!"));
try {
test.get().fail(result.getThrowable(),
--fail---------> MediaEntityBuilder.createScreenCaptureFromPath(getScreenshot()).build());
} catch (IOException e) {
System.err
.println("Exception thrown while updating test fail status " + Arrays.toString(e.getStackTrace()));
}
test.get().getModel().setEndTime(getTime(result.getEndMillis()));
}
public synchronized void onTestSkipped(ITestResult result) {
System.out.println((result.getMethod().getMethodName() + " skipped!"));
try {
test.get().skip(result.getThrowable(),
MediaEntityBuilder.createScreenCaptureFromPath(getScreenshot()).build());
} catch (IOException e) {
System.err
.println("Exception thrown while updating test skip status " + Arrays.toString(e.getStackTrace()));
}
test.get().getModel().setEndTime(getTime(result.getEndMillis()));
}
public synchronized void onTestFailedButWithinSuccessPercentage(ITestResult result) {
System.out.println(("onTestFailedButWithinSuccessPercentage for " + result.getMethod().getMethodName()));
}
private Date getTime(long millis) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(millis);
return calendar.getTime();
}
}
****Base page****
public WebDriver driver;
public Properties prop;
public static boolean highlightElement;
public OptionsManager optionsManager;
By OpenForm = By.xpath("//button[#class='open-button']");
By JobcodeField = By.id("jobCode");
By DraftHTML = By.xpath("//input[#value='Draft HTML']");
By HideForm = By.xpath("//button[contains(text(),'Hide Form')]");
public static ThreadLocal<WebDriver> tldriver = new ThreadLocal<WebDriver>();
public static synchronized WebDriver getDriver() {
return tldriver.get();
}
public WebDriver init_driver(Properties prop) {
String browserName = null;
if (System.getProperty("browser") == null) {
browserName = prop.getProperty("browser");
} else {
browserName = System.getProperty("browser");
}
highlightElement = prop.getProperty("highlight").equals("yes") ? true : false;
System.out.println("Browser Launched:" + " " + browserName);
optionsManager = new OptionsManager(prop);
// public WebDriver init_driver(String browserName) {
// highlightElement = prop.getProperty("highlight").equals("yes") ? true : false;
// System.out.println("Browser Launched:" + " " + browserName);
// optionsManager = new OptionsManager(prop);
if (browserName.equals("chrome")) {
WebDriverManager.chromedriver().setup();
tldriver.set(new ChromeDriver(optionsManager.getChromeOptions()));
} else if (browserName.equals("firefox")) {
WebDriverManager.firefoxdriver().setup();
tldriver.set(new FirefoxDriver(optionsManager.getFirefoxOptions()));
} else if (browserName.equals("internetexplorer")) {
WebDriverManager.iedriver().setup();
tldriver.set(new InternetExplorerDriver(optionsManager.io));
} else {
System.out.println("Browser Name" + " " + browserName + "is not found");
}
getDriver().manage().deleteAllCookies();
getDriver().manage().window().maximize();
if(System.getProperty("url") == null) {
getDriver().get(prop.getProperty("url"));
}else {
getDriver().get(System.getProperty("url"));
}
return getDriver();
}
public Properties init_properties() {
prop = new Properties();
String path = null;
String env = null;
try {
env = System.getProperty("env");
if (env.equals("qa")) {
path = "./src/main/java/gov/gao/qa/config/qa.config.properties";
} else if (env.equals("dev")) {
path = "./src/main/java/gov/gao/qa/config/dev.config.properties";
} else if (env.equals("demo")) {
path = "./src/main/java/gov/gao/qa/config/demo.config.properties";
}
} catch (Exception e) {
path = "./src/main/java/gov/gao/qa/config/config.properties";
}
try {
FileInputStream ip = new FileInputStream(path);
prop.load(ip);
} catch (FileNotFoundException e) {
System.out.println("Configuration Propoeries Issue... correct config.properties file");
} catch (IOException e) {
e.printStackTrace();
}
return prop;
}
public String getScreenshot() {
File src = ((TakesScreenshot) getDriver()).getScreenshotAs(OutputType.FILE); <-----failes
String path = System.getProperty("user.dir") + "/screenshots/" + System.currentTimeMillis() +".png";
File destination = new File(path);
try {
FileUtils.copyFile(src, destination);
} catch (IOException e) {
System.out.println("screenshot captured failed...");
}
return path;
}
}
When i execute the testRunner it gives me:
Exception in thread "main" java.lang.NullPointerException
at gov.gao.qa.base.BasePage.getScreenshot(BasePage.java:284)
at gov.gao.qa.listeners.ExtentReportListener.onTestFailure(ExtentReportListener.java:89)
ExtentReport was copied from website, i am very new to this. Please help.
I'm trying to take screenshots when a test fails and then add them to my report. Currently it takes a screenshot when it opens up the application again to do the extent.flush(); in my afterMethod().
My screenshot class is here:
public class CaptureScreenShot {
private static final DateFormat dateFormat = new SimpleDateFormat("yyy_MM_dd SSS");
public static String captureScreen(WebDriver driver, String screenName) throws IOException {
TakesScreenshot screen = (TakesScreenshot) driver;
File src = screen.getScreenshotAs(OutputType.FILE);
String dest = System.getProperty("user.dir") + "Test-ScreenShots" + screenName + ".png";
File target = new File(dest);
FileUtils.copyFile(src, target);
return dest;
}
public static String generateFileName(ITestResult results) {
Date date = new Date();
return results.getName() + "_" + dateFormat.format(date);
}
}
The report building class is here:
public class ExtentTestNGReportBuilder {
public static ExtentReports extent;
public static ThreadLocal<ExtentTest> parentTest = new ThreadLocal<>();
public static ThreadLocal<ExtentTest> test = new ThreadLocal<>();
private String fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm").format(new Date());
#BeforeSuite
public void beforeSuite() {
extent = ExtentManager.createInstance("MobileCustomerCare " + fileName + ".html");
ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter("C:\\Users\\tom.cockram\\Documents");
extent.attachReporter(htmlReporter);
}
#BeforeClass
public synchronized void beforeClass() {
ExtentTest parent = extent.createTest(getClass().getName());
parentTest.set(parent);
}
#BeforeMethod
public synchronized void beforeMethod(Method method) {
ExtentTest child = parentTest.get().createNode(method.getName());
test.set(child);
}
#AfterMethod
public synchronized void afterMethod(ITestResult result) throws IOException {
AppiumDriver<MobileElement> driver = MetricellTest.setupTests();
String screenShot = CaptureScreenShot.captureScreen(driver, CaptureScreenShot.generateFileName(result));
if (result.getStatus() == ITestResult.FAILURE) {
test.get().log(Status.FAIL, result.getName());
test.get().log(Status.FAIL, result.getThrowable());
test.get().fail("Screen Shot : " + test.get().addScreenCaptureFromPath(screenShot));
test.get().fail(result.getThrowable());
} else if (result.getStatus() == ITestResult.SKIP) {
test.get().skip(result.getThrowable());
} else
test.get().pass("Test passed");
extent.flush();
}
I'm not sure what your question is, but as per my understanding you are just not able to attach the screenshot.Assuming you have to attach it in case of test failures only. Put it in the method onTestFailure.
For screenshots name to append the date and time:
public static String getCurrentDateAndTime(String format) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format);
LocalDateTime now = LocalDateTime.now();
return dtf.format(now).toString();
}
Here I am using the listener for generating reports in HTML format but it is not printing the logs present in a test case.
Sample Test Cases
#Test
public void testRedirectAllControlScreen() throws Exception {
reportLog("login using a valid IsoMetrix username and password.");
HomePage homePage = loginPage.login("username", "password");
reportLog("Go to All Control page");
AllControlPage allControlPage = homePage.navigateToControlPage();
reportLog("Verify All Control page");
allControlPage.verifyAllControlPage();
}
Method Present in BaseClass
public void reportLog(String message) {
message = BREAK_LINE + message;
logger.info("Message: " + message);
Reporter.log(message);
}
ExtentReport Listener
public class ExtentReporterNG implements IReporter {
private ExtentReports extent;
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
extent = new ExtentReports(outputDirectory + File.separator + "ExtentReport.html", true);
for (ISuite suite : suites) {
Map<String, ISuiteResult> result = suite.getResults();
for (ISuiteResult r : result.values()) {
ITestContext context = r.getTestContext();
buildTestNodes(context.getPassedTests(), LogStatus.PASS);
buildTestNodes(context.getFailedTests(), LogStatus.FAIL);
buildTestNodes(context.getSkippedTests(), LogStatus.SKIP);
}
}
extent.flush();
extent.close();
}
private void buildTestNodes(IResultMap tests, LogStatus status) {
ExtentTest test;
if (tests.size() > 0) {
for (ITestResult result : tests.getAllResults()) {
test = extent.startTest(result.getMethod().getMethodName());
test.assignAuthor("360Log");
test.setStartedTime(getTime(result.getStartMillis()));
test.setEndedTime(getTime(result.getEndMillis()));
for (String group : result.getMethod().getGroups())
test.assignCategory(group);
int s = result.getStatus();
if (result.getStatus() == 1) {
test.log(status, "Test " + status.toString().toLowerCase() + "ed");
} else {
String screen = BaseTest.screen;
test.log(status, "Test " + status.toString().toLowerCase() + "ed " + test.addScreenCapture(screen));
}
extent.endTest(test);
}
}
}
}
PFA the screenshot.
Without using listener I am able to achieve the same thing.
I implemented the extent test and extent report in Baseclass.java as per people suggestion like this:
public static ExtentTest test;
public static ExtentReports extent;
#BeforeSuite
public void before() {
extent = new ExtentReports("target\\surefire-reports\\ExtentReport.html", true);
}
#BeforeMethod
public void setUp(Method method) throws Exception {
test = extent.startTest(method.getClass().getSimpleName(),method.getClass().getEnclosingMethod().getName());
test.assignAuthor("Vaibhav");
//Rest code will be generic for browser initiliazion.
}
#AfterSuite
public void tearDownSuite() {
// reporter.endReport();
extent.flush();
extent.close();
}
//Method for adding logs passed from test cases
public void reportLog(String message) {
test.log(LogStatus.INFO, message);//For extentTest HTML report
logger.info("Message: " + message);
Reporter.log(message);
}
Sample Test Case
#Test
public void testRedirectAllControlScreen() throws Exception {
reportLog("login using a valid IsoMetrix username and password.");
HomePage homePage = loginPage.login("username", "password");
reportLog("Go to All Control page");
AllControlPage allControlPage = homePage.navigateToControlPage();
reportLog("Verify All Control page");
allControlPage.verifyAllControlPage();
}
ExtentReport view
The Below Code Works for me for Extent Report version : v2.41.1, Try it!!!
Try Creating an Object of Extent Report and logger as the Below Code.
// Base Class Usage
public static ExtentReports report;
public static ExtentTest logger;
report = new ExtentReports(path);
report.loadConfig(new File("//home//.....//extent-config.xml"));
logger = report.startTest(this.getClass().getSimpleName()).assignCategory("Happy Path"));
// Test Case Usage: Using it at Every Step in Each Test Case
logger.log(LogStatus.INFO,"String Message to Log for Each Step in Test Case");
// #AfterMethod
#AfterMethod(alwaysRun=true)
public void TearDown_AM(ITestResult result) throws IOException
{
System.out.println("#After Method");
try
{
if(result.getStatus()==ITestResult.FAILURE)
{
String res = captureScreenshot(Driver, result.getName());
String image= logger.addScreenCapture(res);
System.out.println(image);
String TestCaseName = this.getClass().getSimpleName() + " Test Case Failure and Title/Boolean Value Failed";
logger.log(LogStatus.FAIL, TestCaseName + logger.addScreenCapture(res));
// logger.log(LogStatus.FAIL, image, this.getClass().getSimpleName() + " Test Case Failure and Title/Boolean Value Failed");
}
else if(result.getStatus()==ITestResult.SUCCESS)
{
logger.log(LogStatus.PASS, this.getClass().getSimpleName() + " Test Case Success and Title Verified");
}
else if(result.getStatus()==ITestResult.SKIP)
{
logger.log(LogStatus.SKIP, this.getClass().getSimpleName() + " Test Case Skipped");
}
report.endTest(logger);
report.flush();
}
catch(Throwable t)
{
logger.log(LogStatus.ERROR,t.fillInStackTrace());
}
}
I know this question is little old but might help someone.
Use this code for buildTestNodes method to print TestNG logs - Reporter.log().
public void buildTestNodes(IResultMap tests, LogStatus status) {
//ExtentTest test = null;
if (tests.size() > 0) {
List<ITestResult> resultList = new LinkedList<ITestResult>(tests.getAllResults());
class ResultComparator implements Comparator<ITestResult> {
public int compare(ITestResult r1, ITestResult r2) {
return getTime(r1.getStartMillis()).compareTo(getTime(r2.getStartMillis()));
}
}
Collections.sort(resultList , new ResultComparator ());
for (ITestResult result : resultList) {
test = extent.startTest(result.getMethod().getMethodName());
test.getTest().setDescription(result.getMethod().getDescription());
test.getTest().setStartedTime(getTime(result.getStartMillis()));
test.getTest().setEndedTime(getTime(result.getEndMillis()));
for(String message:Reporter.getOutput(result)){ **//This code picks the log from Reporter object.**
test.log(LogStatus.INFO, message);
}
for (String group : result.getMethod().getGroups())
test.assignCategory(group);
String message = "Test " + status.toString().toLowerCase() + "ed";
if (result.getThrowable() != null)
message = result.getThrowable().getClass() +": "+ result.getThrowable().getMessage();
test.log(status, message);
extent.endTest(test);
}
}
}
I have written a small program in Java (eclipse) to run R using JRI (rjava). All paths are set. The problem is that while I can run numeric functions (like add), I can't run a string function like cat. (please excuse any errors; I did Java coding for the first time yesterday).
package com.trial.ss;
import org.rosuda.JRI.Rengine;
public class RScriptConnection {
public Rengine getRScriptEngine() throws Exception {
Rengine engine = null;
try {
engine = Rengine.getMainEngine();
if (engine == null) engine = new Rengine(new String[] {
"--vanilla"
},
false, null);
/* if (!engine.waitForR()) {
System.out.println("Unable to load R");
return null;
} else*/
System.out.println("Connected to R");
String rScriptSourceFile = "source('" + RScriptConstant.RS_FILE_LOCATION + "',verbose=TRUE)";
engine.eval(rScriptSourceFile);
System.out.println("loading RScript file || completed");
//return engine;
} catch(Exception ex) {
System.out.println("Exeption while connecting to REngine " + ex.getMessage());
//throw new Exception("Error while creating REngine in RScriptConnection:getRScriptEngine()");
}
return engine;
}
public static void main(String[] args) {
String libpath = System.getProperty("java.library.path");
System.out.println("##############libpath=" + libpath);
// System.out.println("Method to be called in RScript=" + "Add(x1 = " + 10 + ", x2 = " + 20 + ", x3 = " + 30 + ", x4 = " + 50 + ")");
RScriptConnection rScriptConnection = new RScriptConnection();
try {
Rengine rEngine = rScriptConnection.getRScriptEngine();
String Value1 = "\"Advisory\"";
String Value2 = "\"Assurance\"";
double svalue = rEngine.eval("(1+2)").asDouble();
System.out.println("mvalue=" + svalue);
System.out.println("method to be called in RScript is " + "cat(" + Value1 + "," + Value2 + ")");
String value = rEngine.eval("cat(" + Value1 + "," + Value2 + ")").asString();
System.out.println(value);
rEngine.end();
} catch(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Please help me understand why my string function like cat doesn't work.
Here is the output I am currently getting:
##############libpath=C:\Users\myname\Documents\R\win-library\3.3\rJava\jri\x64
Connected to R
loading RScript file || completed
mvalue=3.0
method to be called in RScript is cat("Advisory","Assurance")
null
Why am I getting null in the end? I should get Advisory Assurance
Bellow is an example of how to show R output into Java. You basically have to implement RMainLoopCallbacks.
import org.rosuda.JRI.RMainLoopCallbacks;
import org.rosuda.JRI.Rengine;
import java.util.logging.Logger;
public class Runner {
private static Logger log = Logger.getLogger("Runner");
static class LoggingConsole implements RMainLoopCallbacks {
private Logger log;
LoggingConsole(Logger log) {
this.log = log;
}
public void rWriteConsole(Rengine re, String text, int oType) {
log.info(String.format("rWriteConsole: %s", text));
}
public void rBusy(Rengine re, int which) {
log.info(String.format("rBusy: %s", which));
}
public void rShowMessage(Rengine re, String message) {
log.info(String.format("rShowMessage: %s", message));
}
public String rReadConsole(Rengine re, String prompt, int addToHistory) {
return null;
}
public String rChooseFile(Rengine re, int newFile) {
return null;
}
public void rFlushConsole(Rengine re) {
}
public void rLoadHistory(Rengine re, String filename) {
}
public void rSaveHistory(Rengine re, String filename) {
}
}
Rengine engine = new Rengine(new String[] {"--no-save"}, false, new LoggingConsole(log));
...
// Use the engine somewhere to evaluate a R method and see the output
engine.eval(rScriptSourceFile);
}
I've successfully implemented the simple Java Amazon SWF example called hello_sample. I created the ActivityWorker executable that polls SWF for activity tasks to process. I created the WorkflowWorker executable that polls SWF for decision tasks and I have a WorkflowStarter executable that kicks off the workflow execution. It works as advertised. What I don't understand is how do I configure and add a second activity to run after the first activity?
WorkflowWorker:
public class WorkflowWorker {
private static final AmazonSimpleWorkflow swf = AmazonSimpleWorkflowClientBuilder.defaultClient();
public static void main(String[] args) {
PollForDecisionTaskRequest task_request =
new PollForDecisionTaskRequest()
.withDomain(Constants.DOMAIN)
.withTaskList(new TaskList().withName(Constants.TASKLIST));
while (true) {
System.out.println(
"WorkflowWorker is polling for a decision task from the tasklist '" +
Constants.TASKLIST + "' in the domain '" +
Constants.DOMAIN + "'.");
DecisionTask task = swf.pollForDecisionTask(task_request);
String taskToken = task.getTaskToken();
if (taskToken != null) {
try {
executeDecisionTask(taskToken, task.getEvents());
}
catch (Throwable th) {
th.printStackTrace();
}
}
}
}
private static void executeDecisionTask(String taskToken, List<HistoryEvent> events) throws Throwable {
List<Decision> decisions = new ArrayList<Decision>();
String workflow_input = null;
int scheduled_activities = 0;
int open_activities = 0;
boolean activity_completed = false;
String result = null;
System.out.println("WorkflowWorker is executing the decision task for the history events: [");
for (HistoryEvent event : events) {
System.out.println(" " + event);
switch(event.getEventType()) {
case "WorkflowExecutionStarted":
workflow_input = event.getWorkflowExecutionStartedEventAttributes().getInput();
break;
case "ActivityTaskScheduled":
scheduled_activities++;
break;
case "ScheduleActivityTaskFailed":
scheduled_activities--;
break;
case "ActivityTaskStarted":
scheduled_activities--;
open_activities++;
break;
case "ActivityTaskCompleted":
open_activities--;
activity_completed = true;
result = event.getActivityTaskCompletedEventAttributes().getResult();
break;
case "ActivityTaskFailed":
open_activities--;
break;
case "ActivityTaskTimedOut":
open_activities--;
break;
}
}
System.out.println("]");
if (activity_completed) {
decisions.add(
new Decision()
.withDecisionType(DecisionType.CompleteWorkflowExecution)
.withCompleteWorkflowExecutionDecisionAttributes(
new CompleteWorkflowExecutionDecisionAttributes()
.withResult(result)));
}
else {
if (open_activities == 0 && scheduled_activities == 0) {
ScheduleActivityTaskDecisionAttributes attrs =
new ScheduleActivityTaskDecisionAttributes()
.withActivityType(new ActivityType()
.withName(Constants.ACTIVITY)
.withVersion(Constants.ACTIVITY_VERSION))
.withActivityId(UUID.randomUUID().toString())
.withInput(workflow_input);
decisions.add(
new Decision()
.withDecisionType(DecisionType.ScheduleActivityTask)
.withScheduleActivityTaskDecisionAttributes(attrs));
}
else {
// an instance of HelloActivity is already scheduled or running. Do nothing, another
// task will be scheduled once the activity completes, fails or times out
}
}
System.out.println("WorkflowWorker is exiting the decision task with the decisions " + decisions);
swf.respondDecisionTaskCompleted(
new RespondDecisionTaskCompletedRequest()
.withTaskToken(taskToken)
.withDecisions(decisions));
}
}
ActivityWorker:
public class ActivityWorker {
private static final AmazonSimpleWorkflow swf = AmazonSimpleWorkflowClientBuilder.defaultClient();
private static CountDownLatch waitForTermination = new CountDownLatch(1);
private static volatile boolean terminate = false;
private static String executeActivityTask(String g_species) throws Throwable {
String s = " ******** Hello, " + g_species + "!";
System.out.println(s);
String cwd = Paths.get(".").toAbsolutePath().normalize().toString();
String filename = "g_species.txt";
Path filePath = Paths.get(cwd, filename);
String filePathName = filePath.toString();
BufferedWriter output = null;
try {
File file = new File (filePathName);
output = new BufferedWriter(new FileWriter(file));
output.write(g_species);
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if (output != null) {
output.close();
}
}
return g_species;
}
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
try {
terminate = true;
System.out.println("ActivityWorker is waiting for the current poll request to return before shutting down.");
waitForTermination.await(60, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
// ignore
System.out.println(e.getMessage());
}
}
});
try {
pollAndExecute();
}
finally {
waitForTermination.countDown();
}
}
public static void pollAndExecute() {
while (!terminate) {
System.out.println("ActivityWorker is polling for an activity task from the tasklist '"
+ Constants.TASKLIST + "' in the domain '" + Constants.DOMAIN + "'.");
ActivityTask task = swf.pollForActivityTask(new PollForActivityTaskRequest()
.withDomain(Constants.DOMAIN)
.withTaskList(new TaskList().withName(Constants.TASKLIST)));
String taskToken = task.getTaskToken();
if (taskToken != null) {
String result = null;
Throwable error = null;
try {
System.out.println("ActivityWorker is executing the activity task with input '" + task.getInput() + "'.");
result = executeActivityTask(task.getInput());
}
catch (Throwable th) {
error = th;
}
if (error == null) {
System.out.println("The activity task succeeded with result '" + result + "'.");
swf.respondActivityTaskCompleted(
new RespondActivityTaskCompletedRequest()
.withTaskToken(taskToken)
.withResult(result));
}
else {
System.out.println("The activity task failed with the error '"
+ error.getClass().getSimpleName() + "'.");
swf.respondActivityTaskFailed(
new RespondActivityTaskFailedRequest()
.withTaskToken(taskToken)
.withReason(error.getClass().getSimpleName())
.withDetails(error.getMessage()));
}
}
}
}
}
WorkflowStarter that kicks it all off:
public class WorkflowStarter {
private static final AmazonSimpleWorkflow swf = AmazonSimpleWorkflowClientBuilder.defaultClient();
public static final String WORKFLOW_EXECUTION = "HelloWorldWorkflowExecution";
public static void main(String[] args) {
String workflow_input = "Amazon SWF";
if (args.length > 0) {
workflow_input = args[0];
}
System.out.println("Starting the workflow execution '" + WORKFLOW_EXECUTION +
"' with input '" + workflow_input + "'.");
WorkflowType wf_type = new WorkflowType()
.withName(Constants.WORKFLOW)
.withVersion(Constants.WORKFLOW_VERSION);
Run run = swf.startWorkflowExecution(new StartWorkflowExecutionRequest()
.withDomain(Constants.DOMAIN)
.withWorkflowType(wf_type)
.withWorkflowId(WORKFLOW_EXECUTION)
.withInput(workflow_input)
.withExecutionStartToCloseTimeout("90"));
System.out.println("Workflow execution started with the run id '" +
run.getRunId() + "'.");
}
}
I would recommend to not reinvent the wheel and use the AWS Flow Framework for Java that is officially supported by Amazon. It already implements all the low level details and allows you to focus on a business logic of your workflow directly.
Here is an example worklow that uses three activities (taken from the developer guide).
Activities interface:
import com.amazonaws.services.simpleworkflow.flow.annotations.Activities;
import com.amazonaws.services.simpleworkflow.flow.annotations.ActivityRegistrationOptions;
#ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300,
defaultTaskStartToCloseTimeoutSeconds = 10)
#Activities(version="1.0")
public interface GreeterActivities {
public String getName();
public String getGreeting(String name);
public void say(String what);
}
Activities implementation:
public class GreeterActivitiesImpl implements GreeterActivities {
#Override
public String getName() {
return "World";
}
#Override
public String getGreeting(String name) {
return "Hello " + name;
}
#Override
public void say(String what) {
System.out.println(what);
}
}
Workflow interface:
import com.amazonaws.services.simpleworkflow.flow.annotations.Execute;
import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow;
import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions;
#Workflow
#WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 3600)
public interface GreeterWorkflow {
#Execute(version = "1.0")
public void greet();
}
Workflow implementation:
import com.amazonaws.services.simpleworkflow.flow.core.Promise;
public class GreeterWorkflowImpl implements GreeterWorkflow {
private GreeterActivitiesClient operations = new GreeterActivitiesClientImpl();
public void greet() {
Promise<String> name = operations.getName();
Promise<String> greeting = operations.getGreeting(name);
operations.say(greeting);
}
}
The worker that hosts both of them. Obviously it can be broken into separate activity and workflow workers:
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;
import com.amazonaws.services.simpleworkflow.flow.ActivityWorker;
import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker;
public class GreeterWorker {
public static void main(String[] args) throws Exception {
ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000);
String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID");
String swfSecretKey = System.getenv("AWS_SECRET_KEY");
AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey);
AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config);
service.setEndpoint("https://swf.us-east-1.amazonaws.com");
String domain = "helloWorldWalkthrough";
String taskListToPoll = "HelloWorldList";
ActivityWorker aw = new ActivityWorker(service, domain, taskListToPoll);
aw.addActivitiesImplementation(new GreeterActivitiesImpl());
aw.start();
WorkflowWorker wfw = new WorkflowWorker(service, domain, taskListToPoll);
wfw.addWorkflowImplementationType(GreeterWorkflowImpl.class);
wfw.start();
}
}
The workflow starter:
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;
public class GreeterMain {
public static void main(String[] args) throws Exception {
ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000);
String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID");
String swfSecretKey = System.getenv("AWS_SECRET_KEY");
AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey);
AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config);
service.setEndpoint("https://swf.us-east-1.amazonaws.com");
String domain = "helloWorldWalkthrough";
GreeterWorkflowClientExternalFactory factory = new GreeterWorkflowClientExternalFactoryImpl(service, domain);
GreeterWorkflowClientExternal greeter = factory.getClient("someID");
greeter.greet();
}
}