I'd like to refresh a certain part of a page periodically. Therefore I created a #Scheduled method that applies the changing values accordingly to the widgets.
But the method never executes:
#Controller
#UIScope
public class MyViewPresenter {
private View view;
#Scheduled(fixedRate = 1000)
public void refresh() {
System.out.println("this is never executed. why?");
//view.change...
}
}
When I move this method into my #Configuration class the sysout is printed fine. So in general I can assume the scheduling works as expected. But not in my presenter class. Why?
You need to enable server push feature 11.16. Server Push
In short:
add vaadin-push library to your dependecies
enable pushing (#Push annotation or servlet configuration)
use UI.access(..) for pushing
Related
My Issue:
This is my first time doing tests for Vaadin UI and I am also fairly new to Unit tests in general. My issue is that I can't do anything with my UI components Views because there is no VaadinSession which handles the UI beans. A VaadinSession is never created when using #SpringBootTest. I was able to create tests for my backend since Spring handles those beans, but I can't seem to figure out a way to get Vaadin to start up a session so I can then access the session and do different integration and unit tests.
What I've Tried
TestBench: The Vaadin testbench seemed like a very good option but the issue that I faced was that it doesn't seem to open a VaadinSession whenever I open a ChromeDriver() that goes to the website on my localhost.
Karibu Library: This library seemed like a very good option, but there was one issue, which was that it opens individual UI components that are instantiated, however a couple of my UI Components Classes, uses dependency injection to inject backend services. I cannot instantiate these classes because of the dependeny injection.
The UI Component that I need to access through the VaadinSession.
#Component
#UIScope
#CssImport("./styles/current-info-styles.css")
public class CurrentDayView extends VerticalLayout implements Updatable {
private static final long serialVersionUID = 1L;
//Some code here
#Autowired
public CurrentDayView(NowcastWeatherService nowcastWeatherService, GeoLocationService geoLocationService) {
this.nowcastWeatherService = nowcastWeatherService;
this.geoLocationService = geoLocationService;
//Some Code here
}
//Some code here
My Testbench approach
#RunWith(SpringRunner.class)
#SpringBootTest
public class CurrentDayViewTest extends TestBenchTestCase {
#Test
public void fakeTest() {
Assert.assertTrue(true);
}
#Before
public void startUp() {
System.setProperty("webdriver.chrome.driver", "src/main/resources/drivers/chromedriver.exe");
setDriver(new ChromeDriver());
getDriver().get("http://localhost:8080/");
populateViewWithInformation();
}
#After
public void tearDown() {
getDriver().quit();
}
private void populateViewWithInformation() {
CurrentDayView currentDayView = (CurrentDayView) VaadinSession.getCurrent().getAttribute("current-day-view");
//This is where I get an error because VaadinSession.getCurrent() is null
}
My Final Question:
Does anyone have any idea on how I could have a VaadinSession created or atleast get spring to keep track for Vaadin UI components? If this wasn't clear then please feel free to ask more clarifications relating to my question.
I suggest you give Karibu another shot, it's great for doing these kinds of tests that don't need the app to be running.
Take a look at the Karibu V14 Spring demo project. Pay attention to what Karibu dependency is used. The ApplicationTest#listOrders test contains navigation to a view with autowired dependencies.
The issue with your TestBench test is that TestBench is used to test against a running application, and the tests run in an entirely different process than the actual application.
So when you open the page with the driver, a Vaadin session is created in the application, but you will not be able to access it in your tests, nor will you be able to access any UI state or views. What it allows you to do, however, is to interact with the application as you would do through the browser (clicking buttons, filling in text fields etc.), and to check that the state in the browser is correct, without knowing anything about the server's internal state.
Generally speaking, when you're writing integration tests with TestBench (which is based on Selenium), what you're doing is directing the browser. You're writing Java code, yes, and the code may even be in the same project as your Vaadin UI code, but it can be executed against any URL and what you're interacting with is the browser's DOM. You're describing what the end-user would do: click a button, write some text in an input field, choose an option from a radio button group. The server-side is a black box. After all, if I submit a post on StackOverflow, I can't check if it gets stored in a database - all I can do is look at what I see after I press the "Post your answer" button. If you really want to nitpick, it doesn't even need to be a Vaadin application you're testing with TestBench, as long as the application behaves like one in the browser.
Secondly, you shouldn't store any Components in the VaadinSession. If you open a Vaadin application in multiple browser tabs, each of those tabs will share the same VaadinSession. A single Component instance should only be used inside one browser tab, where the root component is the current UI.
I use Spring boot #scheduled to execute a task periodically. I want to redirect and jump to another page after the periodic execution of the task is completed. However, the process is executed periodically and the message is displayed, but the redirect is not performed.
Please advise me.
enter code here
#Controller
#RequestMapping("/index")
public class TaskController {
#Scheduled(fixedRate = 5000)
public String task(){
System.out.println("test");
return "redirect:/index";
}
}
A method annotated with scheduled is running in your application without any interaction from the outside. So there is no client that could be redirected to anything.
You can only redirect from a method that is called because it is an mapped to a get or put or any other kind of request.
I am writing a service where I want to expose an endpoint which will call another service and if the service call is successful then I want to send back the result to UI/ calling app.
In parallel before sending back the response, I want to execute/submit a task which should run in background and my call should not be dependent on success or failure of this task.
Before returning the response i want to do the-
executorService.execute(object);
This should not be a blocking call..
Any suggestion
Spring Async methods is the way to go here as was suggested in comments.
Some caveats:
Async methods can have different return types, its true that they can return CompletableFuture but this is in case if you called them from some background process and would like to wait/check for their execution status or perhaps, execute something else when the future is ready. In your case it seems that you want "fire-and-forget" behavior. So you should use void return type for your #Async annotated method.
Make sure that you place #EnableAsync. Under that hood it works in a way that it wraps the bean that has #Async methods with some sort of proxy, so the proxy is actually injected into your service. So #EnableAsync turns on this proxy generation mechanism. You can verify that this is the case usually in the debugger and checking the actual type of the injected reference object.
Consider customizing the the task executor to make sure that you're running the async methods with executor that matches your needs. For example, you won't probably want that every invocation of async method would spawn a new thread (and there is an executor that behaves like this). You can read about various executors here for example
Update
Code-wise you should do something like this:
public class MyAsyncHandler {
#Async
public void doAsyncJob(...) {
...
}
}
#Service
public class MyService {
#Autowired // or autowired constructor
private MyAsyncHandler asyncHandler;
public Result doMyMainJob(params) {
dao.saveInDB();
// do other synchronous stuff
Result res = prepareResult();
asyncHandler.doAsyncJob(); // this returns immediately
return res;
}
}
I've finished working on some lengthy method launched from the client side using GWT-RPC. doSomething()
Suppose the following classes: (copied from GWT: invoke the same RPC-methods on the server-side as on the client-side)
//MyClassService.java - client package
#RemoteServiceRelativePath("myService")
public interface MyClassService extends RemoteService{
public doSomething();
}
//MyClassServiceAsync.java - client package
public interface MyClassServiceAsync{
public void doSomething(AsyncCallback<Void> callback);
}
//MyClassServiceImpl.java - server package
public class MyClassServiceImpl extends RemoteServiceServlet implements MyClassService{
#Override
public void doSomething()
{
//interacts with DB and another stuff
}
}
Now I'd wish to launch the very same method from my ScheduledTask infrastructure but I don't know if this is posible. The ScheduledTask infrastructure is in the server side. I've barely worked the networking side of any language and I'm lost. So far I've tried:
MyClassServiceImpl a = new MyClassServiceImpl();
a.doSomething();
The problem appear (NullPointerException) as soon as it hits the first doSomething() line with some call to getServletConfig().getServletContext() as it returns null.
Plus, MyClassServiceImpl init() method which I've overrided so it reads some params from web.xml, is also not invoked.
Thx in advance!
Not specifically GWT related, but:
1) Move your initialization parameters out of web.xml. It is an awful mechanism and should never have been in the servlet specification. If you build a war file, it means that you have to rebuild the war file every time the parameters changes. And if you need to different parameters for dev, acceptance, and prod, that means three separate war files. Instead put a properties file somewhere on the file system. Start your web container with an extra Java parameter setting a value for a custom property, for example -Dmyapp.conf=d:\\conf\\apps\\myapp.conf.
2) Now that you have moved your parameters out of web.xml, you can write a standalone class that initializes itself from the system defined parameters file (System.getProperty("myapp.conf")), with no dependency on anything servlet related.
3) Use the class from your GWT servlet, your scheduler, etc...
In my test application (JSF, PrimeFaces, Wildfly 8) I have a simple messaging interface for writing a message and viewing those that were sent to me. I now would like to create an automatic respond for those messages that were not answered after 5 minutes. This automatic respond is meant to be independent of any person sitting behind the browser window and clicking the refresh button.
My current idea is to create a new class annotated with #ApplicationScoped. This class shall run an individual thread handling the responding process. Would that be a good approach? Or is there a functionality somewhere that already covers this matter?
I think the option worth considering would be to use javax.ejb.TimerService:
#Stateless
public class AutomaticResponseSender {
private static final Integer _5_MINS = 300000;
#Resource
private TimerService timerService;
public void waitFiveMinutes() {
Timer nextTimer = timerService.createSingleActionTimer(_5_MINS, null);
}
#Timeout
public void autoRespondForNotAnswered() {
// here send an auto response
}
public void cancel() {
timerService.cancel();
}
}
Upon sending the manual answer you need to call cancel() to avoid autoresponse or, alternatively, you can check in autoRespondForNotAnswered() method if the answer was send.
Another approach could be to use #Schedule and, let's say every 5 or 10 seconds, check for messages not answered in 5 mins and sending automatic answers for them.