Which scope to use with vaadin and spring? - java

I'd like to develop a vaadin application with spring. A user should be able to login and see uer-specific pages. I he comes to the site from a different browser window, it would be handy if the user is still logged in, so preserves the session.
Now I wonder which scope to use for this purpose? Vaadin and Spring offer a #Scope("session"), #Scope("ui") and a #Scope("prototype"). Should I just place all of my *View and *Presenter classes in the session scope?
Or would it be better to have the view annoted with prototype, so that each time a pages is changed the page is recreated with updated data?
In this case, should then the presenters be still session scope, or also prototye?
Or should I at all use the ui scope that's provided by vaadin4spring boot addon? This would then create a new "uiSession" for every new tab.
#Scope("session")
class MyPresenter {
//each view should be wired to a presenter
#Autowired
private MyView view;
}
#Scope("prototype") //"session", "ui"?
class MyView extends VerticalLayout {
#PostConstruct
public void init() {
addComponent(new Label("time is: " + new Date()));
}
}

vaadin stores (large amounts of) state in the session. state is pretty much anything, that is visible to the client in the browser. the ui scope is what you should use, if any component is involved. even if ui and session seem the same, you should stick to ui to prevent raceconditions and worse against the vaadin code.
in your example above, view is definetly ui, because it is a component. this makes the presenter ui also as it holds reference to an ui scoped component and will for sure tap into events from it or read data etc.

Related

Spring security prevents navigating to another view from a background thread

I have trouble migrating from Vaadin 14 to Vaadin 23. I have a long running backgroundtask with a progress dialog. With Vaadin 14 after finishing the task i could navigate to a result-view with the following code:
UI ui = UI.getCurrent();
final SecurityContext context = SecurityContextHolder.getContext();
ui.access(() -> {
SecurityContextHolder.setContext(context);
UI.navigate("work-finished-view");
});
With Vaadin 23 i get this warning
(ViewAccessChecker.java:147) Preventing navigation to com.vaadin.flow.router.RouteNotFoundError because no HTTP request is available for checking access.
This is the code in com.vaadin.flow.server.auth.ViewAccessChecker
VaadinServletRequest vaadinServletRequest = VaadinServletRequest.getCurrent();
if (vaadinServletRequest == null) {
// This is in a background thread and we cannot access the request
// to check access
getLogger().warn("Preventing navigation to " + targetView.getName()
+ " because no HTTP request is available for checking access.");
beforeEnterEvent.rerouteToError(NotFoundException.class);
return;
}
What is the right way to navigate to another view from a background thread?
You would need create a fake request that uses the values from the security context holder and set that request using CurrentInstance.set(VaadinRequest.class, request);. Completely doable but not very nice.
Instead of writing a long and hacky example here for how it could be done, I spent the time on creating a pull request to make this work out of the box in the future: https://github.com/vaadin/flow/pull/13675
If you are using the VaadinWebSecurityConfigurerAdapter the SecurityContext should automatically be available in the UI thread. Unfortunately, the ViewAccessChecker will not make use of it either way. The way it's implemented (i.e. in a Spring independent way) it simply requires a HttpServletRequest. So I currently don't see a right way to do this (with vanilla Vaadin, anyway). You should probably create a ticket on Github because this seems like a pretty important use case.
Maybe you could redirect to an unprotected view that requires the user to click a button to navigate to the protected one.
Page#setLocation(...) would also create a new request for the security check, but that will not navigate within Vaadin and basically recreate your UI.
But both options are pretty far down on the list of acceptable workarounds, honestly.
If no one else can provide an actually reasonable workaround, you could check out my add-on: Spring Boot Security for Vaadin. It does use Spring's SecurityContext so it would work in your case.

Get new Instace of Controller or Managed Bean

The problem that present here is a solution that I am thinking about a particular situation.
Technology Stack: Primefaces, JSF and Spring Framework.
My application
My Web App shows the result of a report in a DataTable of Primefaces. The report has to open in a new tab of the browser. The datable table uses the filters in the datatable header. I have only one view XHTML where the reports it is showed.
My design
#ViewScope
#Controller
public class MBReport implements Serializable {
private transient LazyDataModel<String[]> lazyData;
public void report1(){
lazyData = new...
}
public void report2(){
lazyData = new...
}
public void report3(){
lazyData = new...
}
//setters and getters
}
My problem
When I show the first report no have problem. When I show the second report no have problem. But, when I try to use the filters of the first report the app crash, because it has lost the reference pointer, and it has been replaced by the second report.
I have the idea if I make a different instance object of the Controller with each request, the problem will be solved, but I cannot to do. I tried with the faces scope (viewscope, flowscope, resquestscope) and Spring beans scope (request, session and application).
The fast solution is to make various View files and lazyData field. But that I don’t like so much.
Could you help me with some ideas for my problem?

Java Servlets - Front Controller Questions (Listeners & Context)

For the current project I'm working on, I've decided to use the front controller pattern. I've always been under the impression that a front controller should (ultimately) be responsible for everything that happens in a web app. Would listeners violate this pattern?
public class MyDatabase implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
...
String driver = context.getInitParameter("driver");
}
}
This, of course, seems a lot simpler than:
public class FrontController extends HttpServlet {
public void service (....) {
MyDatabase db = new MyDatabase(context.getInitParameter("driver"));
}
}
This is a very simplified example; there would be more parameters in practice. So, which snippet would be considered more faithful to the front controller pattern – passing the config from FrontController down, or supplying the config directly to the classes?
As I am new to Java, I am trying to learn servlets without using a framework (for the time being).
Main intent for Front controller is to provide a centralized entry point for handling requests and consequently
to control navigation across a set of related pages (for instance,
multiple pages might be used in an online purchase) from a front
controller than it is to make the individual pages responsible for
navigation
Separating responsibility of initialization of resources from Front controller pattern is good, and you choose a right place for this since ServletContextListener is responsible for receiving notification events about ServletContext lifecycle. Code inside ServletContextListener class will run before the web application starts.

OSGi DS & deactivating a component manually

Is it valid to deactivate a component in OSGi manually if I am using Declarative Services?
For example, let's say I have a component, with the implementation:
//component
class Overseer(){
List<ServiceReference> serviceRefs = ...//populate
private void doStuff(){
serviceRef = serviceRefs[i];
if(dontNeedThisAnymore){
serviceRefs.remove(serviceRef);
serviceRef.getBundle().stop();
}
}
The best way to do this is from another component in the same bundle, using the ComponentContext API.
You can write a component so that it takes ComponentContext as a param to its activate method. That interface has enableComponent and disableComponent methods that can be used to enable/disable other components in the same bundle.
I call this a "gatekeeper" component because it can be used to setup resources needed by the other components before enabling them. For example, you may have multiple components that need a database to be started up before they can do their job... the gatekeeper would take care of starting the database and then call enableComponent(null) to enable the other components. Similarly if the gatekeeper could detect that the database has shutdown and at that point disable the other components. In order for this to work, all components in the bundle except for the gatekeeper need to be set initially to enabled="false".

JSF & Facelets Flow

I have a dynamic Facelets page that needs to show information from database when the page loads. At this point in the flow, there have not been any form submissions. Every JSF example I can find only shows a form submission with dynamic results on the next page.
Every call I make to our database is currently takes place after an action has been triggered by a form submission. Where should this code go if there hasn't been a form submission, and how do I trigger it? A code snippet would really help me out!
You should be able to do your initialization work in the constructor (or lazily in one of your accessors) of your managed bean.
If you're using Spring integration (see here also), it's easy.
In your backing bean, simply use something like:
public class BackingBean implements InitializingBean
{
public void afterPropertiesSet()
{
loadInitialData();
}
}
If you're not integrating with Spring there are two options:
Load the initial data in the class constructor;
In your faces-config.xml, you can set properties to be injected. Properties are guaranteed to be set in the order they're specified in the config file. So, just create a dummy property and then within that method load up your default data. i.e. create a method public void setLoaded(boolean loaded) { loadInitialData(); }, and in your faces-config.xml have 'loaded' being set as a property on that backing bean.
Hope this is all clear!
You write (with my emphasis added):
Every call I make to our database is currently takes place after an action
has been triggered by a form submission. Where should this code go
if there hasn't been a form submission, and how do I trigger it? A
code snippet would really help me out!
It sounds to me that you want to retrieve information from the database prior to form submission.
It seems to me that you want to make an Ajax call to query the database. The Ajax call can fire on a different event than the form submisson event. This will probably entail using Javascript rather than the Faces framework.

Categories

Resources