Invalidate specific jsf bean session [duplicate] - jsf

This question already has answers here:
Removing specific CDI managed beans from session
(2 answers)
Closed 1 year ago.
How I invalidate a specific bean in a session?
I have this example code.
I test with ExternalContext.invalidateSession(); but it destroy all beans in the session in the application since it destroys the full session.
#Named
#SessionScoped
class Managed implements Serializable {
public void invalidate (){
// lines //
externalContext.invalidateSession();
}
}
but, with invalidateSession all beans in the session are destroyed, I want to invalidate only the one specific "Managed" bean, how I do that?

Ignoring the fact that you're not clear on how you want to implement this solution, to start
Inject the BeanManager into wherever you plan to execute the logic. It has to be a managed component
#Inject
BeanManager beanManager;
The bean manager is the component that will grant you access to all the CDI beans (and other stuff) within your context.
You then use the BeanManager to get a contextual reference to the bean you're interested in
Bean<Managed> bean = (Bean<Managed>) beanManager.resolve(beanManager.getBeans(Managed.class));
Managed managedBean= (Managed) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean)
managedBean = null; //or whatever you want to do with it
This solution should destroy the active instance of that session bean; if another attempt is made to use that same bean, CDI will most likely create a brand new instance on-demand

While the approach with BeanManager is viable, I would suggest slightly different approach.
You should be able to #Inject HttpSession into your managed #SessionScoped bean and then invoke invalidate() on that session.
Something along these lines:
#Named
#SessionScoped
class Managed implements Serializable {
#Inject
HttpSession session;
public void invalidate (){
session.invalidate(); //invalidates current session
}
}
Yet another way to achieve this is to make use of FacesContext. You were on the right track but you need to take one extra step:
((HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true)).invalidate();

Related

Re-create session scoped JSF managed bean programmatically

I'm using Mojarra 2.1.29 and have a session scoped JSF managed bean
#ManagedBean
#SessionScoped
public class UserContext{
//staff
}
and a spring bean:
public class UserReproducer{
private User user;
public void reporoduce(){
if(user == null){
//Here I need to recreate the userContext managed bean
//do some other staff
}
}
}
In fact, I need some kind of custom scope in JSF, i.e. to re-create the userContext bean from scratch when the condition is satisfied. Is it possible to do in some way? By recreating, I mean cleaning all its properties down as it was created for the first time.
Invalidate the session, to destroy a session scoped bean:
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
Another option to log out from Spring Security is to clear the context:
SecurityContextHolder.clearContext();

Inject an application scoped managed bean in a websocket

I'm developing a real time application. I have websockets and application scoped managed bean. I'm trying to access the application scoped managed bean from a websocket but I can't. Is this possible?
This is my websocket and managed bean (application scoped):
#ServerEndpoint("/mediador")
#ManagedBean(eager = true)
#ApplicationScoped
public class Mediador implements Serializable {
#ManagedProperty(value = "#{aplicacion}")
private Aplicacion aplicacion;
...
And my "Aplicacion" managed bean:
#ManagedBean(eager = true)
#ApplicationScoped
public class Aplicacion implements Serializable {
...
If I try to access in Mediador class to de managed property "aplicacion" it's null so I get a NullPointerException.
Thanks
This is really not right.
#ServerEndpoint("/mediador")
#ManagedBean(eager = true)
#ApplicationScoped
public class Mediador implements Serializable {
WS (JSR-356 WebSocket) API and JSF API are completely independent from each other. They know nothing from each other and won't take mixed annotations from each other into account.
Effectively, you end up with two instances of the class. One as a WS managed server endpoint as available by ws://.../mediador, and one as a JSF managed bean as available by #{mediador}. The #ManagedProperty is only recognized by JSF managed bean facility and it'll work in the JSF managed bean instance only.
Use CDI instead. It works across the entire Java EE web application. Not only in WebSocket endpoints, but also in JSF managed beans, WebServlets, WebFilters, WebListeners, JAX-RS resources, JAX-WS resources, etcetera. Eventually, JSF managed bean facility will be deprecated in favor of CDI. This will happen in Java EE 9 or perhaps already 8.
#ServerEndpoint("/mediador")
public class Mediador { // Shouldn't be serializable!
#Inject
private Aplicacion aplicacion;
// ... (no getter+setter needed!)
}
#Named
#ApplicationScoped // javax.enterprise.context
public class Aplicacion { // Shouldn't be serializable!
// ...
}
Unrelated to the concrete problem: implementing websockets in JSF rightly is not exactly trivial, certainly not if you'd like to take into account JSF session and view scopes, and would like to be able to target a specific user during push. You'd better look at an existing push component. See also How can server push asynchronous changes to a HTML page created by JSF?

Scope of Stateless Bean

I got a stateless bean like the following:
#Stateless
public class MyBean implements IMyBean {
#Inject
private SomeClass someClass;
#EJB
private MyRepository myRepository;
#Production
#Inject
private SomeFacade someWorker;
#PostConstruct
private void init() {
// some logic ...
}
// some more logic...
}
IMyBean is annotated with #Local.
I am running a JBoss Server. I got a .bat-file which uses MyBean. Only in the first execution of this bat-file the #PostConstruct gets called. Why is that? Which scope has MyBean? It seems like it's at least ApplicationScoped. I thought it would be RequestScope...
Your bean is an EJB before being a CDI bean. Therefore it follows the lifecycle of stateless EJB. The first time you request it, the container create it and call the #PostConstruct callback. When it's not needed anymore, it's not destroyed by returned to the EJB stateless pool, ready to be reused.
From the CDI perspective it's a #Dependent bean: it's CDI part (proxy) is recreated each time you inject it, but the EJB part is provided by the EJB container from the pool.
Looking at CDI spec, the section related to Lifecycle of stateless and singleton session beans states this regarding creation:
When the create() method of a Bean object that represents a stateless
session or singleton session bean is called, the container creates and
returns a container-specific internal local reference to the session
bean. This reference is not directly exposed to the application.
and regarding the the destruction:
When the destroy() method is called, the container simply discards
this internal reference.
Internal reference is discarded but the EJB container keep the bean for futur reuse.
If more than one user ask for this bean at the same time a new EJB might be created and the #PostConstruct will be called. So from the user point of view postConstruct calls may seem random.
The best solution is to put your stateless bean in #ApplicationScoped to avoid strange behavior.

how is the #RequestScoped bean instance provided to #SessionScoped bean in runtime here?

I am reading through this example in JBoss where a #RequestScoped bean backing up JSF page is used to pass the user credential information which is then saved in a #sessionScoped bean.
Here is the example take from JBoss docs.
#Named #RequestScoped
public class Credentials {
private String username;
private String password;
#NotNull #Length(min=3, max=25)
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
#NotNull #Length(min=6, max=20)
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
JSF form:
<h:form>
<h:panelGrid columns="2" rendered="#{!login.loggedIn}">
<f:validateBean>
<h:outputLabel for="username">Username:</h:outputLabel>
<h:inputText id="username" value="#{credentials.username}"/>
<h:outputLabel for="password">Password:</h:outputLabel>
<h:inputSecret id="password" value="#{credentials.password}"/>
</f:validateBean>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
<h:commandButton value="Logout" action="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form>
User Entity:
#Entity
public class User {
private #NotNull #Length(min=3, max=25) #Id String username;
private #NotNull #Length(min=6, max=20) String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String setPassword(String password) { this.password = password; }
}
SessionScoped bean
#SessionScoped #Named
public class Login implements Serializable {
#Inject Credentials credentials;
#Inject #UserDatabase EntityManager userDatabase;
private User user;
public void login() {
List<User> results = userDatabase.createQuery(
"select u from User u where u.username = :username and u.password = :password")
.setParameter("username", credentials.getUsername())
.setParameter("password", credentials.getPassword())
.getResultList();
if (!results.isEmpty()) {
user = results.get(0);
}
else {
// perhaps add code here to report a failed login
}
}
public void logout() {
user = null;
}
public boolean isLoggedIn() {
return user != null;
}
#Produces #LoggedIn User getCurrentUser() {
return user;
}
}
My questions are
1) The #RequestScoped bean gets injected into #SessionScoped bean. What is the guarantee that the credential information set on one instance of RequestScoped is the same that is injected into #SessionScopedbean. why not a different #RequestScoped from pool gets injected or even a new instance?
2)why is the bean given #SessionScoped but not #Stateful. I guess #Stateful will work here.
3)how is the lifecycle of #sessionScoped bean managed? That is when does it gets destroyed ?. If I navigate to a different JSF page in which if I pull the information such as currentUser.userName, will I retrieve the same information I set on my first JSF page used to log in. (step 1 above)
4) If I don't specify #RequestScoped, then the Credentials bean get the #Dependent scope which is the defualt scope. It is mentioned in the docs that setting any instance variables of a #Dependent gets lost immediately. But I don't understand why? In fact, this prompts me the question of what use of #Dependent scope will be ?
Thanks
EDIT
Thanks kolossus for detailed and excellent answer. I need a little more clarifications on some of your points for better understanding
For a #requestScoped bean, there are is a pool of instances available which gets handed over to clients. Now if I have two clients accessing a JSF which is backed by a #RequestScoped bean, each client gets to work on one instance of #RequestScoped bean from the pool. In fact, both the clients do not actually work on the direct instance, but an indirect reference to the that single instance which is the proxy here. clients do all method calls or transactions using this proxy. so how long does the proxy holds this indirect reference? That is, in my example above, instance variables of #RequestScoped bean (Credentials) are set in JSF. but the true fact is that, this setting of instance variables happen to one instance of #RequestScoped bean indirectly through proxy. But when this instance is injected into SessionScoped bean, is it the proxy that gets injected? Since the lifecycle of SessionScoped is for a session established between client and application, does the proxy also live during this lifetime. Does that mean this single instance of #RequestScoped bean is bound to SessionScoped and the lifecycle of #RequestScoped bean instance or its proxy is determined by the lifecycle of SessionScoped bean?
The #RequestScoped bean gets injected into #SessionScoped bean. What is the guarantee that the credential information set on one instance of RequestScoped is the same that is injected into #SessionScopedbean. why not a different #RequestScoped from pool gets injected or even a new instance?
This is legal, thanks to the means by which CDI actually obtains references to a requested bean: client proxies. From the CDI spec
An injected reference, or reference obtained by programmatic lookup, is usually a contextual reference.A contextual reference to a bean with a normal scope[...], is not a direct reference to a contextual instance of the bean[...].Instead, the contextual reference is a client proxy object
A client proxy implements/extends some or all of the bean types of the bean and delegates all method calls to the current instance of the bean...
There are a number of reasons for this indirection:
The container must guarantee that when any valid injected reference to a bean of normal scope is invoked, the invocation is always processed by the current instance of the injected bean. In certain scenarios, for example if a request scoped bean is injected into a session scoped bean, or into a servlet, this rule requires an indirect reference
Also from this DZone CDI article:
CDI handles the injection of beans with mismatched scopes through the use of proxies. Because of this you can inject a request scoped bean into a session scoped bean and the reference will still be valid on each request because for each request, the proxy re-connects to a live instance of the request scoped bean
What this means is that, a proxy is substituted for the real thing at each injection point. The proxy mimics the type declared at the injection point by extending/implementing the ancestor tree of the type it's supposed to be mimicking. At the time you now actually require use of the object, the proxy performs a context-based lookup for an existing instance of the requested bean within the current conversation. This being a request-scoped object, you're guaranteed to have exactly one instance within the current conversation/context.
why is the bean given #SessionScoped but not #Stateful. I guess #Stateful will work here.
#Stateful would not work here, like I stated here, they are not cheap; unless you really need to, stick with vanilla HttpSession. Not to mention the fact that once the client of the SFSB releases the bean it's destroyed, i.e. the SFSB is not tied to the current session,#SessionScoped is.
how is the lifecycle of #sessionScoped bean managed? That is when does it gets destroyed ?. If I navigate to a different JSF page in which if I pull the information such as currentUser.userName, will I retrieve the same information I set on my first JSF page used to log in. (step 1 above)
Depends on which #SessionScoped you're referring to: javax.faces.bean.SessionScoped is tied directly to the current HttpSession/browser session, so it's terminated whenever that dies; JBoss however implies that javax.enterprise.context.* scoped beans don't actually go anywhere until the "context" dies
There's actually no way to remove a bean from a context until the entire context is destroyed
Think of #Dependent as you would any method-local variable: it's only useful as long as it's parent construct is around. That being said, it's best use is not for backing a JSF view. It's most useful application is overriding the scope that's specified on a bean, ad-hoc. Using your current example, I can have the following somewhere else in my application:
#Inject #New Login aDependentLoginBean; //implicit #Dependent scope applied
#Inject Login aSessionScopedLoginBean; //standard Login bean's scope applied
Together with #New, you could repurpose any other bean to be #Dependent
Related:
Is it possible to #Inject a #RequestScoped bean into a #Stateless EJB?

How do I force an application-scoped bean to instantiate at application startup?

I can't seem to find a way to force an application-scoped managed bean to be instantiated/initialized when the web app is started. It seems that application-scoped beans get lazy-instantiated the first time the bean is accessed, not when the web app is started up. For my web app this happens when the first user opens a page in the web app for the first time.
The reason I want to avoid this is because a number of time-consuming database operations happen during the initialization of my application-scoped bean. It has to retrieve a bunch of data from persistent storage and then cache some of it that will be frequently displayed to the user in the form of ListItem elements, etc. I don't want all that to happen when the first user connects and thus cause a long delay.
My first thought was to use an old style ServletContextListener contextInitialized() method and from there use an ELResolver to manually request the instance of my managed bean (thus forcing the initialization to happen). Unfortunately, I can't use an ELResolver to trigger the initialization at this stage because the ELResolver needs a FacesContext and the FacesContext only exists during the lifespan of a request.
Does anyone know of an alternate way to accomplish this?
I am using MyFaces 1.2 as the JSF implementation and cannot upgrade to 2.x at this time.
My first thought was to use an old style ServletContextListener contextInitialized() method and from there use an ELResolver to manually request the instance of my managed bean (thus forcing the initialization to happen). Unfortunately, I can't use an ELResolver to trigger the initialization at this stage because the ELResolver needs a FacesContext and the FacesContext only exists during the lifespan of a request.
It doesn't need to be that complicated. Just instantiate the bean and put it in the application scope with the same managed bean name as key. JSF will just reuse the bean when already present in the scope. With JSF on top of Servlet API, the ServletContext represents the application scope (as HttpSession represents the session scope and HttpServletRequest represents the request scope, each with setAttribute() and getAttribute() methods).
This should do,
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("bean", new Bean());
}
where "bean" should be the same as the <managed-bean-name> of the application scoped bean in faces-config.xml.
Just for the record, on JSF 2.x all you need to do is to add eager=true to #ManagedBean on an #ApplicationScoped bean.
#ManagedBean(eager=true)
#ApplicationScoped
public class Bean {
// ...
}
It will then be auto-instantiated at application startup.
Or, when you're managing backing beans by CDI #Named, then grab OmniFaces #Eager:
#Named
#Eager
#ApplicationScoped
public class Bean {
// ...
}
Romain Manni-Bucau posted a neat solution to this that uses CDI 1.1 on his blog.
The trick is to let the bean observe the initialization of the built-in lifecycle scopes, i.e. ApplicationScoped in this case. This can also be used for shutdown cleanup. So an example looks like this:
#ApplicationScoped
public class ApplicationScopedStartupInitializedBean {
public void init( #Observes #Initialized( ApplicationScoped.class ) Object init ) {
// perform some initialization logic
}
public void destroy( #Observes #Destroyed( ApplicationScoped.class ) Object init ) {
// perform some shutdown logic
}
}
As far as I know, you can't force a managed bean to be instantiated at application startup.
Maybe you could use a ServletContextListener which, instead of instantiating your managed bean, will perform all the database operations itself?
Another solution might be to instantiate your bean manually at application startup, and then set the bean as an attribute of your ServletContext.
Here is a code sample:
public class MyServletListener extends ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
MyManagedBean myBean = new MyManagedBean();
ctx.setAttribute("myManagedBean", myManagedBean);
}
}
In my opinion, this is far from clean code, but it seems like it does the trick.
Additionally to BalusC's answer above you could use #Startup and #Singleton (CDI), e.g.
//#Named // javax.inject.Named: only needed for UI publishing
//#Eager // org.omnifaces.cdi.Eager: seems non-standard like taken #Startup below
#Startup // javax.ejb.Startup: like Eager, but more standard
#Singleton // javax.ejb.Singleton: maybe not needed if Startup is there
//#Singleton( name = "myBean" ) // useful for providing it with a defined name
#ApplicationScoped
public class Bean {
// ...
}
which is nicely explained here.
Works in JPA 2.1 at least.

Resources