lunes, 15 de abril de 2019

12. Vaadin Session, CDI and CdiVaadinServlet

updated April 15, 2019

0. Introduction

We need to store information in sessions. This can be achieved basically in 2 ways:
  1. Adding attributes to the session. The session has a map of attributes.
  2. Using session-scoped beans. Using CDI is a good choice.

1. Adding parameters to the Session.

As seen in the previous post,  the session can be accessed.  Here is an example of accessing the session and getting or setting an attribute. The utility class "VaadinUtils" is used. The attribute has a name and an object type value.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package stuff;
import openadmin.utils.VaadinUtils;

public class TestAttributes {

 public static void main(String[] args) {
  VaadinUtils.setSessionAttribute("CONNECTED_USER", "Ximo");
  System.out.println(VaadinUtils.getSessionAttribute("CONNECTED_USER").toString()); }

}

It is necessary knowing who is the connected user. So a session attribute whose name is "CONNECTED_USER" will be created. This attribute will be used to allow or deny the user to use the application.

2. Using CDI and session-scoped beans


To use CDI in Vaadin let's follow these 4 steps:

2.1 Create a class that extends CdiVaadinServlet

This class is informing about:
  1. The use of CDI (as it extends CdiVaadinServlet instead of VaadinServlet)
  2. The class that manages the i18n (internationalization) of the application. We will review this step later in another post.
  3. If the production mode is activated (by means of annotations)
Her is the code (in the "openadmin.listeners" package)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package openadmin.listeners;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

import com.vaadin.cdi.CdiVaadinServlet;
import com.vaadin.flow.server.Constants;
//import com.vaadin.flow.server.VaadinServlet;
import com.vaadin.flow.server.VaadinServletConfiguration;

/**
 * Information about app servlet 
 * 
 * Necessary for defining i18n Provider
 * @author ximo 
 *
 */
@SuppressWarnings("serial")
@WebServlet(
 urlPatterns = "/*", 
 name = "slot", 
 asyncSupported = true, 
 initParams = {
  // I18N Provider for translation of labels 
        @WebInitParam( 
         name = Constants.I18N_PROVIDER, value = "openadmin.i18n.MyI18nProvider") 
        
 })

@VaadinServletConfiguration(productionMode = false)

//public class ApplicationServlet extends VaadinServlet {
public class ApplicationServlet extends CdiVaadinServlet {
}



Note that:

  1. The class only informs. No procedures are defined.
  2. The class "openadmin.i18n.MyI18nProvider" is the class that manages "i18n".
  3. The @VaadinServletConfiguration annotations is used to inform that we are not in production mode.
  4. If no CDI is used, then this class should extend "VaadinServlet".

2.2 Create a the session-scoped bean

Now a simple class with only one attribute is created as an example. Note that attributes will be added in the future. Note that:

  1. CDI specific annotations (@Named and @SessionScoped) are no longer compatible. The @VaadinSessionScoped is used instead!
  2. To avoid "NullPointerException" when accessing the injected instance of this class, a method annotated with @PostConstruct and this method should initialize information of the class. This method is used to remove the "CONNECTED_USER" attribute from the session. 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package openadmin.session;

import javax.annotation.PostConstruct;
//import javax.enterprise.context.SessionScoped;
//import javax.inject.Named;

import com.vaadin.cdi.annotation.VaadinSessionScoped;
import openadmin.utils.VaadinUtils;

import lombok.Getter;
import lombok.Setter;

//@Named @SessionScoped
@VaadinSessionScoped
public class SessionData {
 @Getter @Setter
 private String something=null;
 
 @PostConstruct
 private void init() {
  something="something else!";
  System.out.println("SessionData.init() called.");
  // Remove the session attribute that informs the user, if exists
  VaadinUtils.getWrappedSession().removeAttribute("CONNECTED_USER");
 }
}

2.3 Inject the session bean into another class


Here is the sample code using the @Inject annotation


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package openadmin.ui;

import javax.inject.Inject;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.PWA;

import openadmin.session.SessionData;

/**
 * The main view contains a button and a click listener.
 */
@SuppressWarnings("serial")
@Route("")
@PWA(name = "Project Base for Vaadin Flow", shortName = "Project Base")
public class MainForm extends VerticalLayout {

 @Inject 
 private SessionData mySesData;
 
    public MainForm() {
     mySesData.setSomething("Something again");
        var button = new Button("Click me. Right Now!",
                event -> Notification.show("Clicked! Silly Boy v.04.1" + mySesData.getSomething()));
        add(button);
    }
}

2.4 Create the file beans.xml


Follow these steps:

  1. In Eclipse go to "Deployed Resources" folder
  2. Go to "webapp" folder
  3. Create the "WEB-INF" folder if not exists
  4. Create the empty file beans.xml




2 comentarios:

  1. Hello.
    Thanks for the article.
    Using Vaadin 14 with spring boot, SessionData class annotations only worked with @Named and @VaadinSessionScope, without @Named spring returns error.

    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'br.com.....view.ListaTrabalhosView': Unsatisfied dependency expressed through field 'mySesData'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'br.com....spring.SessionData' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject()}

    ResponderEliminar
  2. I am not very good at this matter. I am avoiding to use Spring as it has too many dependencies. So I use Vaadin with a simple Tomcat and WELD CDI as CDI provider and it works. Now I am migrating to Vaadin 14 and there are some changes. I will get you informed.

    ResponderEliminar