Dostęp do sesscion scoped CDI bean z poziomu request scoped CDI bean

0

Muszę otrzymać dostęp do session scoped CDI bean z poziomu request scoped CDI bean.

  • Session scoped CDI bean (LoginController) utrzymuje zalogowanego w serwisie użytkownika;
  • Request scoped CDI bean (DataServiceImpl) przetwarza pewne dane i potrzebuje do tego celu obiektu zalogowanego użytkownika.

Obecnie kiedy próbuje otrzymać dostęp do session bean z poziomu request bean - otrzymuję wyjątek NullPointerException w tej linijce:
String surname=loginController.getCurrentUser().getSurname();
Dla jasności, wyjątek nie jest spowodowany metodą getCurrentUser(), a już samym obiektem loginController, który został wstrzyknięty do request bean'a. Oczywiście z poziomu każdego widoku mogę odwołać się do tego obiektu poprzez #{loginController.currentUser.surname} i wszystko działa bez problemu, ale potrzebuje dostęp z poziomu bean'a, a nie widoku.

Ma ktoś jakiś pomysł na rozwiązanie problemu?

Część strony logowania:

<h:form class="form">               

    <p:growl id="growl" showDetail="false" />

    <pm:field>
        <h:inputText id="username" value="#{userLogin.username}" label="Username" required="true" requiredMessage="Username: This field is required." title="Enter your username." pt:placeholder="Username" />                     
    </pm:field>

    <pm:field>
        <h:inputSecret  id="password" value="#{userLogin.password}" label="Password" required="true" requiredMessage="Password: This field is required." title="Enter your password." pt:placeholder="Password" />
    </pm:field>                 

    <p:commandButton value="Login" action="#{loginController.login}" update="growl" styleClass="buttonStyle"/>                  

</h:form>

Session scoped CDI bean:

@Named
@SessionScoped
public class LoginController implements Serializable {

    private static final long serialVersionUID = -6322113716363932422L;

    public String login(){      

        if(userService.login(userLogin)){

            currentUser=userService.getCurrnetUser(userLogin.getUsername());

            return "home?faces-redirect=true";          
        }
        else{

            facesContext.addMessage(null, new FacesMessage("Data entered are incorrect"));
            return null;
        }
    }

    public String logout(){

        currentUser=null;

        return "login?faces-redirect=true";
    }

    public boolean isLoggedIn() {

          return currentUser!=null;
    }

    @Produces
    @LoggedIn
    public UserAccount getCurrentUser(){

        return currentUser; 
    }   

    @Inject
    private FacesContext facesContext;

    @Inject
    private UserServiceImpl userService;

    @Named
    @Produces
    @RequestScoped
    private UserAccount userLogin=new UserAccount();

    private UserAccount currentUser;
}

Request scoped CDI bean:

@Named
@RequestScoped
public class DataServiceImpl implements DataService {

    @Override
    public void addData(String[] data) {

        //Proccess some data

        String surname=loginController.getCurrentUser().getSurname();

        //Proccess some data
    }

    @Inject
    private LoginController loginController;

    @Inject
    private DataDao dataDao;
}

Aktualizacja:

  • Dodanie bean'a DataController , który podobnie jak LoginController jest kontrolerem dla pewnego widoku. Posiada wstrzyknięty bean DataServiceImpl, który wykorzystuje w send().

View scoped CDI bean:

@Named
@ViewScoped
public class DataController implements Serializable {

    private static final long serialVersionUID = 1383572529241805730L;

    //some methods

    public void send(){

        if(uploadFile==null){

            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "The file isn't uploaded", "You should upload the file"));
        }
        else{

            list=new ArrayList<String>();

            //Here should be the uploaded file but for now I added it manually.
            try(Stream<String> stream=Files.lines(Paths.get("F:/VirtualBox/Share/capture20110815.binetflow"))) {            

                list=stream.collect(Collectors.toList());

                int start=0;                
                Pattern pattern=Pattern.compile(",");
                dataService=new DataServiceImpl();

                for (String s : list) {

                    if(start!=0){

                        String[] data=pattern.split(s);

                        dataService.addData(data);
                    }
                    else start++;
                }                           

            } catch (IOException e) {

                e.printStackTrace();
            }       

            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "The data has been added.", ""));           
        }
    } 

    @Inject
    private DataService dataService;

    @Inject
    private Logger log;

    private UploadedFile uploadFile;
    private List<String> list;
}
1

Ja tu nie widzę błędu, może po prostu nie zalogowałeś użytkownika? Mam jednak kilka uwag.

  • Kontrolery nie powinny być @SessionScoped
  • możesz wstrzyknąć użytkownika przez @Inject @LoggedIn UserAccount currentUser, a nie LoginController
  • zrób sobie osobną klasę Credentials na nazwę użytkownika i hasło
  • do logowania/wylogowywania użytkownika powinieneś użyć HttpServletRequest#login/logout. HttpServletRequest możesz uzyskać tak: (HttpServletRequest)FacesContext.getExternalContext.getRequest(); . Wtedy też zamiast isLoggedIn mógłbyś użyć HttpServletRequest#getUserPrincipal()
  • FacesContext nie jest wstrzykiwalne przed JSF2.3 (którego jeszcze nie ma)
    PS. JavaEE przeżywa ostatnio ciężkie chwile https://adtmag.com/blogs/watersworks/2016/03/java-ee-guardians.aspx
0

Dzięki za rady - zastosuję. Właśnie przez przypadek znalazłem zarówno rozwiązanie jak i chochlika, który chyba był winowajcą mojego problemu. Zaktualizowałem swój pierwszy post i dodałem jeszcze view scoped CDI bean (DataController), który okazuje się chyba brakującym puzzlem w układance.

Dla uporządkowania: bean DataController jest kontrolerem dla pewnego widoku. Ma wstrzyknięty m.in. bean DataServiceImpl, w którym to z kolei jest wstrzyknięty wspomniany wcześniej bean LoginController. Jak można zauważyć, w metodzie send() klasy DataController wywołuję metodę addData() klasy DataServiceImpl.

Nawigacja jest następująca:
widok -> kontroler DataController -> wywołanie dataService.addData() w metodzie send() klasy DataController -> wykonanie metody addData() klasy DataServiceImpl

Teraz do sedna:

  • Wstrzyknięcie zarówno mojego LoginController jak i Twojego UserAccount do DataServiceImpl - nie działa (tj. w obu przypadkach obiekt zwraca null).
  • Wstrzyknięcie zarówno mojego LoginController jak i Twojego UserAccount do DataController - powoduję, że wszystko działa jak należy (tj. obiekt zwraca mi zalogowanego użytkownika).

De faco wystarczy stworzyć jakąś metodę w klasie DataServiceImpl i przekazać przez parametr obiekt zalogowanego użytkownika, a następnie wywołać tę metodę gdzieś w klasie DataController przed wywołaniem dataService.addData().

Nie rozumie z kolei, dlaczego wstrzyknięcie obiektu do DataServiceImpl nie działa (tj. zwraca null), a do DataController działa. Jest ktoś w stanie to wytłumaczyć?

PS. Odnośnie artykułu - ciekawy, zobaczymy co się z tego wykluje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1