Listening to when the user session is ended in a JSF managed bean - session

Is it possible to do something like this: When a user session starts I read a certain integral attribute from the database. As the user performs certain activities in this session, I update that variable(stored in session) & when the session ends, then I finally store that value to the DB.
My question is how do I identify using the JSF framework if the user session has ended & I should then store the value back to DB?

Apart from the HttpSessionListener, you can use a session scoped managed bean for this. You use #PostConstruct (or just the bean's constructor) and #PreDestroy annotations to hook on session creation and destroy
#ManagedBean
#SessionScoped
public class SessionManager {
#PostConstruct
public void sessionInitialized() {
// ...
}
#PreDestroy
public void sessionDestroyed() {
// ...
}
}
The only requirement is that this bean is referenced in a JSF page or as #ManagedProperty of any request scoped bean. Otherwise it won't get created. But in your case this should be no problem as you're apparently already using a session scoped managed bean, just adding a #PreDestroy method ought to be sufficient.

My question is how do I identify using
the JSF framework if the user session
has ended & I should then store the
value back to DB?
The JSF framework does not have a separate concept of a session; it uses the underlying session management features of the Servlet specification.
You would have to create a HttpSessionListener that provides hooks for you to capture the session creation and destruction events, where you can read the value and store it back into the DB.

HttpSessionListener, or if you need Dependency Injection for that save, you might use #PostConstruct & #PreDestroy. Remember that the session is destroyed when you call invalidate() or after session timeout, not when the user closes the browser. Why do you use Session Scope anyway, Conversation Scope might fit you better.

Related

Tomcat JSF Session BEan #Predestroy "Session already invalidated"

So I try to access an attribute of my HttpSession on my #PreDestroy method on a #SessionScoped JSF managed bean using
session.getAttribute("myAttribute");
But I get a
java.lang.IllegalStateException: getAttribute: Session has already been invalidated
Why?
I need to access the list of connections to external services opened by that session before one of my session beans is destroyed, and they are of course stored on a session attribute object.
How can I do that?
Explicitly accessing a session attribute in a session scoped managed bean doesn't make sense. Just make that attribute a property of the session scoped managed bean itself.
#SessionScoped
public class YourSessionScopedBean implements Serializable {
private Object yourAttribute; // It becomes a session attribute already.
#PreDestroy
public void destroy() {
// Just access yourAttribute directly, no need to do it the hard way.
}
}
The exception you faced occurred because the session was explicitly invalidated via a HttpSession#invalidate() call instead of "just" expired.

What are the techniques to manage "session" or invocation context for Stateless EJBs during Remote calls?

I am writing an application that uses RMI to invoke EJBs. The EJBs are Stateless; the business requirements do not require conversational state with the client.
One of the parameters to the EJB method calls is a "User" object used to determine if the user associated with the call has permission to perform the action. We are not using container-managed auth-auth: the User object is just a POJO provided by the remote client.
I would like to make this User object globally available/injectable within the "session" or invocation context. I am aware that Stateless EJBs do not have a "session" in the EJB sense; what I mean by "session" is "the current invocation". For example, say we have only one remote EJB with two methods:
myStatelessEjb.add(Thing, User)
myStatelessEjb.update(Thing, User)
These methods call many more methods: there are other EJBs involved, Bean Validators, etc. Rather than passing-around the User object everywhere, I would like to make the User object globally available/injectable with the context of the current remote EJB invocation.
I could of course just pass around the User object or encapsulate it with "Thing", but I thought maybe it would be a better design to not "pollute" my objects and APIs with User since it's a cross-cutting concern.
Notes (for emphasis):
I am using RMI.
There is no HTTP session, because I am using RMI.
I am not using container-managed auth-auth.
I am using container-managed transactions.
Is there a standard technique suitable for this problem? e.g. Perhaps the remote client should invoke a Stateful EJB which will hold the User, or maybe ThreadLocal is appropriate, or maybe I can hook onto the container-managed transaction, or maybe there's already an applicable session/context I'm unaware of.
Easiest way would be to store the user in a #RequestScoped CDI bean and inject that as required:
#RequestScoped
public class RequestUser {
private User user;
//getter and setter for user
}
#Remote
#Statless
public class MyRemoteInterface {
#Inject
private RequestUser requestUser;
...
public void foo(User user, Bar bar) {
request.setUser(user);
...
}
}
#Stateless
public class OtherEJB() {
#Inject
private RequestUser user;
public void doBar(Bar bar) {
User user = user.getUser();
...
}
}
While #SessionScoped is useful for HTTP sessions only, #RequestScoped has broader applicability:
public #interface RequestScoped
Specifies that a bean is request scoped.
The request scope is active:
during the service() method of any servlet in the web application, during the doFilter() method of any servlet filter and when the
container calls any ServletRequestListener or AsyncListener,
during any Java EE web service invocation,
during any remote method invocation of any EJB, during any asynchronous method invocation of any EJB, during any call to an EJB
timeout method and during message delivery to any EJB message-driven
bean, and
during any message delivery to a MessageListener for a JMS topic or queue obtained from the Java EE component environment.

EJB 3.0 , are thread safe?

Hy,
I am a newbie in EJB. Now I am studying the EJB 3.0 specification. If I have two different JSF managed beans like the next ones:
#ManagedBean
public class CocheBean {
#EJB
private ICochesService cochesService = null;
}
#ManagedBean
public class UsuarioBean {
#EJB
private ICochesService cochesService = null;
}
The injecteds implementations for cochesService are the same in both cases?, I mean, for each annotation, the ejb container gets back a new object or is the same object?
Why do they refer to EJBs as session beans? Are they session scoped? Do they exist till the session of a user expires?
Its said that you dont have to worry if the stateless EJB are thread safe because the container has a pool of different instances for each request but if they are stateless and there is no danger that multiple threads access to just one ejb, why the container creates a pool of them and not just one?
Using JSF managed beans, if this bean is request or session scoped and because we inject the ejbs in this beans, they cannot be called more than once per user or per request at the same time, right?
How to specify the transactional atributes to EJB bean methods, with JPA annotations?
Thanks
This depends - if ICochesService is stateless than each of them will have different object. If it's stateful or singleton than both beans will have the same object injected
Answer to both questions is no :) See the Oracle docs
Exactly
You can call as many beans as you want per each request.
See the Oracle tutorial for Java Transaction API.

when will JSF #PostConstruct be called again?

I'm making an application with spring+primefaces
I created a init function in managed bean to load some useful data (the bean is #ViewScope)
#PostConstruct
public void init(){
log.debug("initing....");
currentUser = UserUtil.getCurrentUser(this.userManager);
loadData();
}
later in view I have some tags to hide columns like this:
<p:column rendered="#{dataManagedBean.currentUser.manager}"> // to test if the current user is a manager role
...
...
</p:column>
the problem is when I login with a normal user, then even logout and login with manager user, the column I want to show is not showing, because the init() method is not calling again therefore the "currentUser" remains the oldone (normal suer)
UPDATE
the problem maybe I mixed Spring DI and JSF managed beans, there is more detail
in javabean layer: I used #Entity annotation for hibernate
in dao layer: I use #Repository("DataDao") to inject the daos (from
spring)
in manager layer: I use use many spring annotations to inject like
#Service("DataManager") #Authowire #Qualifier etc
in view layer, since I have been using spring to inject, thats why I
use #Component("DataManagedBean") and #ViewScope
I have been 2 weeks with the application, and everything worked as expected. untill I found today #PostConstruct is actually never call again, the view is never destroy :S (or it's intented to work like this, a singleton...)
Can someone kindly explain me where I did wrong?
After an intensive reading about JSF scopes, specially thanks to #M. Deinum's comments and Mr #BalusC's excelent article explaining about the JSF communication topic. I understand why the user object survived event after logout/relogin.
My mistake is combining Spring DI (by using #Component annotation) and JSF annotation (by using #ViewScoped), then the #ViewScoped annotation is ignored and default spring scope is used, which is by default a singleton...

How to inject a JSF bean into a spring bean

I'm working on a legacy JSF application which we are slowly porting over to Spring MVC. We are using Spring Security to control login information. After logging the user in, the JSF pages globally instantiate a session scoped bean that is used everywhere. I'd like to change the application so that we can go to a page that was developed with Spring MVC first.
One approach I tried was to convert the bean into a spring bean and have it injected into JSF, but unfortunately that turned out to require a lot of changes to the bean to make it possible. One possible hack I thought of is to add a special redirecting JSF page to initialize the JSF beans before sending the user to the Spring MVC page. That seems like quite a bit of a hack though so I'm looking for another solution.
Is there some other way that I can force the session scoped bean to be initialized before I go to my Spring pages so that I can just pull the bean out of session?
If you are using Spring MVC, you can make your "bean" a Model Attribute, then have it auto-loaded into session using a combination of annotations on the Controller, handler methods, and a method that creates an instance of your bean. Your controller would look something like this:
#Controller
#SessionAttributes({"myBean"})
#RequestMapping("/myPath")
public class MyController {
#RequestMapping("/myPath2")
public String myHandler(#ModelAttribute("myBean") MyBean myBean) {
// ...do stuff, return view
}
#ModelAttribute("myBean")
MyBean createMyBean() {
// Create and init an instance
return new MyBean();
}
}
You will get a MyBean magically created for you whenever there isn't one, and any time you update the Model (or ModelAndView) with "myBean", it will also get magically added to the Session.

Resources