I am trying to call asynchronous method that returns Future Object, I suppose that it will print YYY and then XXX since the XXX is in a method that is 1 sec long. however, after deploying the code, it did not work properly, I tried the same thing with 10 objects and they printed sequentially. where is the error
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package testfuture;
import java.net.InetAddress;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.ejb.Asynchronous;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
#Singleton
#TransactionManagement(TransactionManagementType.BEAN)
public class TestFuture {
#Schedule(minute = "*/1", hour = "*", persistent = false)
public void start() {
try{
Future<String> r = inparallelMethod(5) ;
System.out.print("YYY");
r.get();
}
catch ( InterruptedException ie )
{
System.out.print(ie.getMessage());
}
catch (ExecutionException e)
{
System.out.print(e.getMessage());
}
}
#Asynchronous
public Future<String> inparallelMethod(int i) throws InterruptedException
{
Thread.sleep(1000);
System.out.print("XXX");
return null;
}
}
Because you call inparallelMethod inside the instanced class "bybassing" container managmenet of calling an async menthod.
You have to define the async method in another bean, #Inject that bean and call the method.
#Singleton
#TransactionManagement(TransactionManagementType.BEAN)
public class TestFuture {
#Inject
AsyncService service;
#Schedule(minute = "*/1", hour = "*", persistent = false)
public void start() {
try{
Future<String> r = service.inparallelMethod(5) ;
System.out.print("YYY");
r.get();
}
catch ( InterruptedException ie )
{
System.out.print(ie.getMessage());
}
catch (ExecutionException e)
{
System.out.print(e.getMessage());
}
}
}
#Stateless
public class AsyncService {
#Asynchronous
public Future<String> inparallelMethod(int i) throws InterruptedException
{
Thread.sleep(1000);
System.out.print("XXX");
return null;
}
}
I post the code to make work the async but your code in very poor to test an async scenario, Thread.sleep inside a java-ee is a very bad practice because thread are managed by container and you can't know wich thread you are really sleeping!
Related
I was wondering if there was a way to pass arguments the a class extending the Service class from the Javafx concurrent package. I would like ProteinariumThread to take in a String argument like ClusterID seen below:
public class ProteinariumThread extends Service<String>{
String ClusterID = "q";
#Override
protected Task<String> createTask(){
return new Task<String>() {
#Override
protected String call() throws Exception {
updateMessage("Running Proteinarium");
System.out.println("Asleep");
ProteinariumRun.PRun(ClusterID);
System.out.println("Woke Up");
String woke = "Woke Up";
return woke;
}
};
}
}
Currently in order to run this background task I use the following bit of code:
final ProteinariumThread service = new ProteinariumThread();
service.start();
This however does not allow me to take in a String argument. Is there anyway to make it that service.start() is able to take in String arguments so that String variable ClusterID can come from outside of the ProteinariumThread class?
final ProteinariumThread service = new ProteinariumThread();
service.start(ClusterID);
You just need to give your service class a constructor and/or method which accepts the necessary argument. As services are meant to be reusable, it'd probably be best to allow configuration throughout the service's lifetime by exposing a property:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
public class ProteinariumService extends Service<String> {
private final StringProperty clusterId = new SimpleStringProperty(this, "clusterId");
public final void setClusterId(String clusterId) { this.clusterId.set(clusterId); }
public final String getClusterId() { return clusterId.get(); }
public final StringProperty clusterIdProperty() { return clusterId; }
public ProteinariumService() {}
public ProteinariumService(String clusterId) {
setClusterId(clusterId);
}
#Override
protected Task<String> createTask() {
return new Task<>() {
final String clusterId = getClusterId(); // cache configuration
#Override
protected String call() throws Exception {
...
}
};
}
}
It's important you copy the needed state from the service to the task since the task is executed on a background thread.
Then when you need to change the cluster ID you just do:
// or bind the property to something in the UI (e.g. a TextField)
theService.setClusterId(newClusterId);
theService.start();
If you really want to be able to do that in one line you can always define an overload for start in your service class:
public void start(String clusterId) {
setClusterId(clusterId):
start();
}
I'm trying to implement a Contract test on Java as described there.
I paste the first test's code in my project and changed import static net.corda.testing.NodeTestUtils.ledger; to import static net.corda.testing.node.NodeTestUtils.ledger;
package com.template;
import org.junit.Test;
import static net.corda.testing.node.NodeTestUtils.ledger;
public class CommercialPaperTest {
#Test
public void emptyLedger() {
ledger(l -> {
return null;
});
}
}
And I see that ledger method has an absolutely different signature, so Java says that it cannot resolve method ledger(<lambda expression>).
What am I doing wrong?
There is an error on that page. The first argument to ledger should be a MockServices instance.
For example, we might write:
public class CommercialPaperTest {
private static final TestIdentity megaCorp = new TestIdentity(new CordaX500Name("MegaCorp", "London", "GB"));
private MockServices ledgerServices;
#Before
public void setUp() {
ledgerServices = new MockServices(
singletonList("net.corda.finance.contracts"),
megaCorp,
makeTestIdentityService(megaCorp.getIdentity())
);
}
#Test
public void emptyLedger() {
ledger(ledgerServices, l -> {
return null;
});
}
}
I created a custom error page to replace the default whitelabel based on this tutorial. It worked fine but I need to pass other attributes to the page so I changed my code to intercept the error endpoint based on the geoand's answer here.
Here is my final code:
#Controller
public class ErroHandlerController implements ErrorController {
#Value("${terena.midas.location}")
private String midasLocation;
#RequestMapping("/error")
public String handleError( Model model ) {
model.addAttribute( "midasLocation", midasLocation );
return "error";
}
#Override
public String getErrorPath() {
return "/error";
}
}
Well the code worked sending my variable midasLocation but I lost the error details like path, status,message, etc... How can I bring them back again?
You need to use the ErrorAttributes which "provides access to error attributes which can be logged or presented to the user".
Take a look:
at how the default Spring Error Controller does it: BasicErrorController.java
LogicBig -
Spring Boot - Using ErrorAttributes in our custom ErrorController
Basic functionality:
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.context.request.WebRequest;
#Controller
public class ErrorHandler implements ErrorController {
private final ErrorAttributes errorAttributes;
public ErrorHandler(ErrorAttributes errorAttributes) {
this.errorAttributes = errorAttributes;
}
#GetMapping("/error")
public String handleError(Model model, WebRequest webRequest) {
model.addAttribute("midasLocation", "xxx");
final Throwable error = errorAttributes.getError(webRequest);
model.addAttribute("exception", error);
model.addAttribute("message", error == null ? "" : error.getMessage());
return "error";
}
#Override public String getErrorPath() {
return "/error";
}
#GetMapping("/throwErrorForTest")
public String throwError() {
throw new RuntimeException("my exception");
}
}
I deploy a Spring MVC webapp on Tomcat 8.5 with the following controller:
import java.util.concurrent.Callable;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class AppController {
#RequestMapping(value="getOkSync", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody String getOkSync() {
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "ok";
}
#RequestMapping(value="getOkAsync", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody Callable<String> getOkAsync() {
return new Callable<String>() {
#Override
public String call() {
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "ok";
}
};
}
}
while the first method returns after 60 sec the correct result, the second method returns after approximately 30 seconds with HTTP response code 500 and the corresponding Spring class logs
Could not complete async processing due to timeout or network error.
(if the delay is set on the other hand to 20 seconds both metods return "ok" after 20 seconds as expected).
Is the timeout controlled by Spring MVC or by Tomcat? What is the property which controls the timeout?
Well, the following works (i.e. both methods return now "ok" after 60 seconds), though there is an interaction between Spring and Tomcat which I do not understand completely at the moment (in any case it appears that if I don't set the property via Spring, the timeout will be that of Tomcat, though I don't know how to set the latter)
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="my.base.package")
public class AppConfig extends WebMvcConfigurerAdapter implements WebApplicationInitializer {
#Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
// TODO Auto-generated method stub
configurer.setDefaultTimeout(120000);
super.configureAsyncSupport(configurer);
}
...
I looked at the documentation and all it says is to create a servlet... With what?
Is there code I need to use for this servlet?
Does it just need to be blank and have the name of postResults?
Is there a provided ant script for this?
I can't find anything on google or selenium's site that lets me in on this.
Thanks
UPDATE: I found the following example
<servlet>
<servlet-name>postResults</servlet-name>
<servlet-class>com.thoughtworks.selenium.results.servlet.SeleniumResultsServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>postResults</servlet-name>
<url-pattern>/postResults</url-pattern>
</servlet-mapping>
However I can't seem to find this Class file anywhere in my selenium jars. I have the RC and regular core downlaods but no dice. Where do I get this jar file from?
If you are using the pure html/javascript capabilities of Selenium like I am then you know that you do not get a results report when testing unless you have a postResults servlet setup somewhere to push the results to.
I found a solution by taking apart the fitRunner plug-in to determine what I would need to get one setup.
This is a java solution btw.
http://jira.openqa.org/browse/SEL-102 you can download a zip file here with everything you would need and a bunch of stuff you don't need.
In your webapp just add the servlet mapping you find in the web.xml to your web app.
make sure the package your reference is created as such below
Then add the following jars you will find in the zip to your web app library if you don't already have them.
jstl.jar
and
standard.jar
create two classes
your.package.path.SeleniumResultServlet
paste the following code in it.
package com.your.package.path;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SeleniumResultsServlet extends HttpServlet {
private static TestResults results;
public static TestResults getResults() {
return results;
}
public static void setResults(TestResults testResults) {
results = testResults;
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (request.getParameter("clear") != null) {
results = null;
ServletOutputStream out = response.getOutputStream();
out.println("selenium results cleared!");
} else {
forwardToResultsPage(request, response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String result = request.getParameter("result");
String totalTime = request.getParameter("totalTime");
String numTestPasses = request.getParameter("numTestPasses");
String numTestFailures = request.getParameter("numTestFailures");
String numCommandPasses = request.getParameter("numCommandPasses");
String numCommandFailures = request.getParameter("numCommandFailures");
String numCommandErrors = request.getParameter("numCommandErrors");
String suite = request.getParameter("suite");
int numTotalTests = Integer.parseInt(numTestPasses) + Integer.parseInt(numTestFailures);
List testTables = createTestTables(request, numTotalTests);
results = new TestResults(result, totalTime,
numTestPasses, numTestFailures, numCommandPasses,
numCommandFailures, numCommandErrors, suite, testTables);
forwardToResultsPage(request, response);
}
private List createTestTables(HttpServletRequest request, int numTotalTests) {
List testTables = new LinkedList();
for (int i = 1; i <= numTotalTests; i++) {
String testTable = request.getParameter("testTable." + i);
System.out.println("table " + i);
System.out.println(testTable);
testTables.add(testTable);
}
return testTables;
}
private void forwardToResultsPage(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("results", results);
request.getRequestDispatcher("/WEB-INF/jsp/viewResults.jsp").forward(request, response);
}
public static class TestResults {
private final String result;
private final String totalTime;
private final String numTestPasses;
private final String numTestFailures;
private final String numCommandPasses;
private final String numCommandFailures;
private final String numCommandErrors;
private final String suite;
private final List testTables;
public TestResults(String postedResult, String postedTotalTime,
String postedNumTestPasses, String postedNumTestFailures,
String postedNumCommandPasses, String postedNumCommandFailures,
String postedNumCommandErrors, String postedSuite, List postedTestTables) {
result = postedResult;
numCommandFailures = postedNumCommandFailures;
numCommandErrors = postedNumCommandErrors;
suite = postedSuite;
totalTime = postedTotalTime;
numTestPasses = postedNumTestPasses;
numTestFailures = postedNumTestFailures;
numCommandPasses = postedNumCommandPasses;
testTables = postedTestTables;
}
public String getDecodedTestSuite() {
return new UrlDecoder().decode(suite);
}
public List getDecodedTestTables() {
return new UrlDecoder().decodeListOfStrings(testTables);
}
public String getResult() {
return result;
}
public String getNumCommandErrors() {
return numCommandErrors;
}
public String getNumCommandFailures() {
return numCommandFailures;
}
public String getNumCommandPasses() {
return numCommandPasses;
}
public String getNumTestFailures() {
return numTestFailures;
}
public String getNumTestPasses() {
return numTestPasses;
}
public String getSuite() {
return suite;
}
public Collection getTestTables() {
return testTables;
}
public String getTotalTime() {
return totalTime;
}
public int getNumTotalTests() {
return Integer.parseInt(numTestPasses) + Integer.parseInt(numTestFailures);
}
}
}
then go ahead and create a UrlDecoder class in the same package
package your.package.path;
import java.io.UnsupportedEncodingException;import java.net.URLDecoder;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* #author Darren Cotterill
* #author Ajit George
* #version $Revision: $
*/
public class UrlDecoder {
public String decode(String string) {
try {
return URLDecoder.decode(string, System.getProperty("file.encoding"));
} catch (UnsupportedEncodingException e) {
return string;
}
}
public List decodeListOfStrings(List list) {
List decodedList = new LinkedList();
for (Iterator i = list.iterator(); i.hasNext();) {
decodedList.add(decode((String) i.next()));
}
return decodedList;
}
}
In your web-inf create a folder called jsp
copy the viewResults.jsp into it that is in the zip file.
copy the c.tld to the /web-inf
restart your server
if you get some goofy errors when trying to load the postResults servlet from selenium try changing the taglib reference int the viewResults.jsp to use the sun url instead due to different version dependencies it may not work. servlet 1.0 vs. 2.0 stuff.
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Then when you run the test runner and choose automatic option in your selenium screen you will have a postResults servlet that you can use and customize at will.
Hope this helps others. Having a way to format test results is a great help when trying to create documentation and the stuff that comes out of the zip with regular selenium doesn't give you this basic functionality and you have to bake it up yourself.
The postResults servlet is useful in a continuous integration environment where you want to have the selenium test results sent to a URL of your choosing ( I believe it's configurable when setting up your selenium test ) and then have that server include the selenium results as part of the build results. If you don't want to do any post-processing on the selenium test results, then you don't have to setup a postResults servlet at all.