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.
Related
When i am trying to run my selenium tests the first test seem to work correctly but then i am recieving this error for the subsequent tests, Im after switching my tests over to an electron app so not sure if this is after causing a issue :
org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
My set up page is:
public class SetUp extends TestRail {
private static ChromeDriver browser;
public static String urlHost;
public static String testEnv;
public static PageConfig pageConfig;
#Before
public void initialBrowser() {
if(browser == null) {
String projectLocation = System.getProperty("user.dir");
System.setProperty("webdriver.chrome.driver", projectLocation + "/chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage");
options.addArguments("start-maximized");
options.addArguments("--disable-gpu");
options.addArguments("disable-infobars");
System.setProperty("webdriver.chrome.silentOutput", "true");
options.setBinary("C:/Users/ElectronApp.exe");
browser = new ChromeDriver(options);
//--------------------
pageConfig = new PageConfig(browser);
}
}
//method: To get the url configs for the environment used to run the test
//#parameter: dev or test. demo doesn't not have a separate front end url
public void beforeTest(#NotNull final String env) throws Exception {
testEnv = env;
System.out.println("TEST ENVIRONMENT: " + testEnv);
switch (env){
case "qa-84" :
urlHost = "http://ukdc1-docker-mx:84/qa/#/login";
break;
case "qa-85":
urlHost = "http://ukdc1-docker-mx:85/qa/#/login";
break;
default:
throw new Exception("Incorrect environment passed");
}
}
//method to close the browser after every cucumber scenario
#After
public void closeBrowser(Scenario scenario) throws IOException, APIException {
if(scenario.isFailed()){
try{
TakesScreenshot screenshot = (TakesScreenshot)browser;
File source = screenshot.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(source, new File("logs/screenshots/" + scenario.getName() + ".png"));
System.out.println("Screenshot taken");
} catch (Exception e){
System.out.println("Exception while taking screenshot " + e.getMessage());
}
}
browser.quit();
writeResultToTestRail(scenario);
}
public void writeResultToTestRail(Scenario scenario) throws IOException, APIException {
String tesCaseID = new String();
for(String s: scenario.getSourceTagNames()){
if(s.contains("TestRail")){
int size = s.length();
int startOfID = s.indexOf('"');
tesCaseID = s.substring(startOfID + 1,size - 2);
}
Map data = new HashMap();
if(scenario.isFailed()){
data.put("status_id", 5);
data.put("comment", "Test Env: " + urlHost + "\n\n" + logError(scenario));
}else {
data.put("status_id", 1);
}
postTestCaseStatus("add_result_for_case/","3914", tesCaseID, data);
//3914
}
}
protected void getTestCaseDetailsInConsole(String testCaseId) throws IOException, APIException {
System.out.println(getTestCaseDetails(testCaseId));
}
private static String logError(Scenario scenario) {
try {
Class klass = ClassUtils.getClass("cucumber.runtime.java.JavaHookDefinition$ScenarioAdaptor" );
Field fieldScenario = FieldUtils.getField(klass, "scenario", true);
if (fieldScenario != null) {
fieldScenario.setAccessible(true);
Object objectScenario = fieldScenario.get(scenario);
Field fieldStepResults = objectScenario.getClass().getDeclaredField("stepResults" );
fieldStepResults.setAccessible(true);
ArrayList<Result> results = (ArrayList<Result>) fieldStepResults.get(objectScenario);
for (Result result : results) {
if (result.getError() != null) {
System.out.println(result.getError() + "\n\n" + result.getErrorMessage());
if(result.getErrorMessage().length() > 3100) {
return result.getErrorMessage().substring(0, 3100);
} else {
return result.getErrorMessage();
}
}
}
}
return "Fetching error logs from the scenario ran into some issue, please check jenkins logs";
} catch (IllegalAccessException | NoSuchFieldException | ClassNotFoundException e) {
return e.getMessage();
}
}
}
And My Page config:
public class PageConfig {
public ChromeDriver browser;
public PageConfig(ChromeDriver browser){
this.browser = browser;
}
//method: Get instance method can be called on any class, it helps to avoid to add a line every time a new PO is added to the project.
//#parameter: ClassName.class
//#example: PageConfig.GetInstance(LoginPage.class).onLoginPage(); where onLoginPage is an method of
LoginPage.
public <TPage extends BasePage> TPage GetInstance (Class<TPage> pageClass){
try {
return initElements(browser, pageClass);
}catch(Exception e){
e.printStackTrace();
throw e;
}
}
}
the error shows that your driver close before the execution of the code, so the code of #After is directly executed so what I think is that you forget to use #Test in your set up page because there is #Before and #After but I don't see #Test.
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!!
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'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();
}
}
I have problem of playing back the recorded media file from red5 published stream, following is my code. I could see a file called out.flv is created, but this out.flv can not be played back.
public class Red5ClientTest {
private static Timer timer;
private static RTMPClient client;
private static String sourceStreamName;
private static int videoTs;
private static int audioTs;
private static FLVWriter writer;
private static int bytesRead =0;
public static void main(String[] args) throws IOException {
String sourceHost = "localhost";
int sourcePort = 1935;
String sourceApp = "oflaDemo";
sourceStreamName = "myStream";
timer = new Timer();
client = new RTMPClient();
String path = "c:\\temp\\out.flv";
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
writer = new FLVWriter(file,true);
client.setStreamEventDispatcher(new StreamEventDispatcher());
client.setStreamEventHandler(new INetStreamEventHandler() {
public void onStreamEvent(Notify notify) {
System.out.printf("onStreamEvent: %s\n", notify);
ObjectMap<?, ?> map = (ObjectMap<?, ?>) notify.getCall().getArguments()[0];
String code = (String) map.get("code");
System.out.printf("<:%s\n", code);
if (StatusCodes.NS_PLAY_STREAMNOTFOUND.equals(code)) {
System.out.println("Requested stream was not found");
client.disconnect();
}
else if (StatusCodes.NS_PLAY_UNPUBLISHNOTIFY.equals(code)
|| StatusCodes.NS_PLAY_COMPLETE.equals(code)) {
System.out.println("Source has stopped publishing or play is complete");
client.disconnect();
}
}
});
client.setConnectionClosedHandler(new Runnable() {
public void run() {
if (writer != null) {
writer.close();
}
System.out.println("Source connection has been closed, proxy will be stopped");
System.exit(0);
}
});
client.setExceptionHandler(new ClientExceptionHandler() {
#Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
System.exit(1);
}
});
// connect the consumer
Map<String, Object> defParams = client.makeDefaultConnectionParams(sourceHost, sourcePort,
sourceApp);
// add pageurl and swfurl
defParams.put("pageUrl", "");
defParams.put("swfUrl", "app:/Red5-StreamRelay.swf");
// indicate for the handshake to generate swf verification data
client.setSwfVerification(true);
// connect the client
client.connect(sourceHost, sourcePort, defParams, new IPendingServiceCallback() {
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
ObjectMap<?, ?> map = (ObjectMap<?, ?>) call.getResult();
String code = (String) map.get("code");
if ("NetConnection.Connect.Rejected".equals(code)) {
System.out.printf("Rejected: %s\n", map.get("description"));
client.disconnect();
//proxy.stop();
}
else if ("NetConnection.Connect.Success".equals(code)) {
// 1. Wait for onBWDone
timer.schedule(new BandwidthStatusTask(), 2000L);
Object result = call.getResult();
System.out.println("Red5ClientTest.main()");
}
else {
System.out.printf("Unhandled response code: %s\n", code);
}
}
});
// keep sleeping main thread while the proxy runs
// kill the timer
//timer.cancel();
System.out.println("Stream relay exit");
}
/**
* Handles result from subscribe call.
*/
private static final class SubscribeStreamCallBack implements IPendingServiceCallback {
public void resultReceived(IPendingServiceCall call) {
System.out.println("resultReceived: " + call);
Object result = call.getResult();
System.out.println("results came {}" + result);
}
}
private static final class StreamEventDispatcher implements IEventDispatcher {
public void dispatchEvent(IEvent event) {
System.out.println("ClientStream.dispachEvent()" + event.toString());
try {
//RTMPMessage build = RTMPMessage.build((IRTMPEvent) event);
IRTMPEvent rtmpEvent = (IRTMPEvent) event;
ITag tag = new Tag();
tag.setDataType(rtmpEvent.getDataType());
if (rtmpEvent instanceof VideoData) {
videoTs += rtmpEvent.getTimestamp();
tag.setTimestamp(videoTs);
}
else if (rtmpEvent instanceof AudioData) {
audioTs += rtmpEvent.getTimestamp();
tag.setTimestamp(audioTs);
}
IoBuffer data = ((IStreamData) rtmpEvent).getData().asReadOnlyBuffer();
tag.setBodySize(data.limit());
tag.setBody(data);
try {
writer.writeTag(tag);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("writting....");
}
catch (Exception e) {//IOException
e.printStackTrace();
}
}
}
private static final class BandwidthStatusTask extends TimerTask {
#Override
public void run() {
// check for onBWDone
System.out.println("Bandwidth check done: " + client.isBandwidthCheckDone());
// cancel this task
this.cancel();
// create a task to wait for subscribed
timer.schedule(new PlayStatusTask(), 1000L);
// 2. send FCSubscribe
client.subscribe(new SubscribeStreamCallBack(), new Object[] { sourceStreamName });
}
}
private static final class PlayStatusTask extends TimerTask {
#Override
public void run() {
// checking subscribed
System.out.println("Subscribed: " + client.isSubscribed());
// cancel this task
this.cancel();
// 3. create stream
client.createStream(new CreateStreamCallback());
}
}
/**
* Creates a "stream" via playback, this is the source stream.
*/
private static final class CreateStreamCallback implements IPendingServiceCallback {
public void resultReceived(IPendingServiceCall call) {
System.out.println("resultReceived: " + call);
int streamId = ((Number) call.getResult()).intValue();
System.out.println("stream id: " + streamId);
// send our buffer size request
if (sourceStreamName.endsWith(".flv") || sourceStreamName.endsWith(".f4v")
|| sourceStreamName.endsWith(".mp4")) {
client.play(streamId, sourceStreamName, 0, -1);
}
else {
client.play(streamId, sourceStreamName, -1, 0);
}
}
}
}
what could I be doing possibly wrong here?
Finally got it
public class TeqniRTMPClient {
private static final Logger logger = LoggerFactory.getLogger(MyRtmpClient.class);
public static void main(String args[]) throws IOException {
TeqniRTMPClient client = new TeqniRTMPClient("localhost", 1935, "oflaDemo", "myStream");
client.recordStream();
}
private RTMPClient client;
private ITagWriter writer;
private String sourceHost;
private int sourcePort;
private String sourceApp;
private String sourceStreamName;
private int lastTimestamp;
private int startTimestamp = -1;
public TeqniRTMPClient(String sourceHost, int sourcePort, String sourceApp,
String sourceStreamName) {
super();
this.sourceHost = sourceHost;
this.sourcePort = sourcePort;
this.sourceApp = sourceApp;
this.sourceStreamName = sourceStreamName;
}
public void recordStream() throws IOException {
client = new RTMPClient();
String path = "c:\\temp\\out.flv";
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
FLVService flvService = new FLVService();
flvService.setGenerateMetadata(true);
try {
IStreamableFile flv = flvService.getStreamableFile(file);
writer = flv.getWriter();
}
catch (Exception e) {
throw new RuntimeException(e);
}
client.setStreamEventDispatcher(new StreamEventDispatcher());
client.setStreamEventHandler(new INetStreamEventHandler() {
public void onStreamEvent(Notify notify) {
System.out.printf("onStreamEvent: %s\n", notify);
ObjectMap<?, ?> map = (ObjectMap<?, ?>) notify.getCall().getArguments()[0];
String code = (String) map.get("code");
System.out.printf("<:%s\n", code);
if (StatusCodes.NS_PLAY_STREAMNOTFOUND.equals(code)) {
System.out.println("Requested stream was not found");
client.disconnect();
}
else if (StatusCodes.NS_PLAY_UNPUBLISHNOTIFY.equals(code)
|| StatusCodes.NS_PLAY_COMPLETE.equals(code)) {
System.out.println("Source has stopped publishing or play is complete");
client.disconnect();
}
}
});
client.setExceptionHandler(new ClientExceptionHandler() {
#Override
public void handleException(Throwable throwable) {
throwable.printStackTrace();
System.exit(1);
}
});
client.setConnectionClosedHandler(new Runnable() {
public void run() {
if (writer != null) {
writer.close();
}
System.out.println("Source connection has been closed, proxy will be stopped");
System.exit(0);
}
});
// connect the consumer
Map<String, Object> defParams = client.makeDefaultConnectionParams(sourceHost, sourcePort,
sourceApp);
// add pageurl and swfurl
defParams.put("pageUrl", "");
defParams.put("swfUrl", "app:/Red5-StreamRelay.swf");
// indicate for the handshake to generate swf verification data
client.setSwfVerification(true);
// connect the client
client.connect(sourceHost, sourcePort, defParams, new IPendingServiceCallback() {
public void resultReceived(IPendingServiceCall call) {
System.out.println("connectCallback");
ObjectMap<?, ?> map = (ObjectMap<?, ?>) call.getResult();
String code = (String) map.get("code");
if ("NetConnection.Connect.Rejected".equals(code)) {
System.out.printf("Rejected: %s\n", map.get("description"));
client.disconnect();
}
else if ("NetConnection.Connect.Success".equals(code)) {
// 1. Wait for onBWDone
client.createStream(new CreateStreamCallback());
Object result = call.getResult();
System.out.println("Red5ClientTest.main()");
}
else {
System.out.printf("Unhandled response code: %s\n", code);
}
}
});
}
class CreateStreamCallback implements IPendingServiceCallback {
public void resultReceived(IPendingServiceCall call) {
System.out.println("resultReceived: " + call);
int streamId = ((Number) call.getResult()).intValue();
System.out.println("stream id: " + streamId);
// send our buffer size request
if (sourceStreamName.endsWith(".flv") || sourceStreamName.endsWith(".f4v")
|| sourceStreamName.endsWith(".mp4")) {
client.play(streamId, sourceStreamName, 0, -1);
}
else {
client.play(streamId, sourceStreamName, -1, 0);
}
}
}
class StreamEventDispatcher implements IEventDispatcher {
private int videoTs;
private int audioTs;
public void dispatchEvent(IEvent event) {
System.out.println("ClientStream.dispachEvent()" + event.toString());
try {
IRTMPEvent rtmpEvent = (IRTMPEvent) event;
logger.debug("rtmp event: " + rtmpEvent.getHeader() + ", "
+ rtmpEvent.getClass().getSimpleName());
if (!(rtmpEvent instanceof IStreamData)) {
logger.debug("skipping non stream data");
return;
}
if (rtmpEvent.getHeader().getSize() == 0) {
logger.debug("skipping event where size == 0");
return;
}
byte dataType = rtmpEvent.getDataType();
ITag tag = new Tag();
tag.setDataType(dataType);
if (rtmpEvent instanceof VideoData) {
VideoData video = (VideoData) rtmpEvent;
FrameType frameType = video.getFrameType();
videoTs += rtmpEvent.getTimestamp();
tag.setTimestamp(videoTs);
}
else if (rtmpEvent instanceof AudioData) {
audioTs += rtmpEvent.getTimestamp();
tag.setTimestamp(audioTs);
}
IoBuffer data = ((IStreamData) rtmpEvent).getData().asReadOnlyBuffer();
tag.setBodySize(data.limit());
tag.setBody(data);
try {
writer.writeTag(tag);
}
catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("writting....");
}
catch (Exception e) {//IOException
e.printStackTrace();
}
}
}
}