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?
Related
I need to modify a user session object (SessionScoped bean - CDI) in a Servlet, so I have to obtain that bean somehow. I used injection in the following way:
#Inject
private UserSession user;
where UserSession is the SessionScoped CDI bean. user methods are called from either doPost or doGet servlet methods.
This works perfectly; every time the #Inject annotation injects the appropriate UserSession bean, but I don't understand how this behavior is achieved.
I assumed that the beans, annotated with #Inject, are injected only once (when the object - Servlet instance in this case - is created), but it is obviously a wrong presumption.
So, when are these beans injected into the servlet? Per request? And how does this approach avoids conflicts (one servlet instance - multiple threads to deal with it) when there are multiple UserSession objects?
The CDI uses the proxy pattern. The injected instance is actually not the real instance, but a proxy which locates the real instance depending on the current context and delegates all methods to it (like as how EJBs work). The autogenerated class of your UserSession bean looks roughly like this:
public UserSessionCDIProxy extends UserSession implements Serializable {
public String getSomeProperty() {
UserSession instance = CDI.resolveItSomehow();
return instance.getSomeProperty();
}
public void setSomeProperty(String someProperty) {
UserSession instance = CDI.resolveItSomehow();
instance.setSomeProperty(someProperty);
}
}
This mechanism allows you to inject instances of a narrower scope in instances of a broader scope and allows you to still get the expected instance in the current context. The standard JSF #ManagedProperty annotation doesn't support it, simply because it does not use a proxy, but injects the desired instance directly. That's why it's not possible to inject something of a narrower scope by #ManagedProperty.
See also:
Backing beans (#ManagedBean) or CDI Beans (#Named)?
Get JSF managed bean by name in any Servlet related class
When using #EJB, does each managed bean get its own #EJB instance?
How to choose the right bean scope?
Your answer lies in the C of CDI, which stands for Contexts.
What happens is that not the actual bean is injected, but a proxy. This proxy is contextual and resolves to the actual session scoped bean depending on the context of the caller on who's behalf the proxy is executed.
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();
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.
I have a JSF2 project (Mojarra on GlassFish 3.1).
I have a ViewScoped bean that references services through a utility class like so:
#ManagedBean
#ApplicationScoped
public static class ServicesUtil {
#EJB
UserService userService;
#EJB
EmailService emailService;
/** getters/setters **/
}
and
#ManagedBean
#ViewScoped
public class UserHandler {
public String method() {
ServicesUtil.getUserService().doUserStuff();
return "newPage";
}
}
My question is, since the ServicesUtil is ApplicationScoped, does that mean there is only one instance of each service for the entire application? And is this bad practice? If done correctly, would the CDI in GlassFish actually create new instances as they are needed?
Similarly, if the Services were injected into the UserHandler instead would the application be more scalable?
The reason we added the ServicesUtil layer is one of my coworkers said that he occasionally had problems getting the injection to work in the Handler when it is ViewScope. Should there be any difficulty using #EJB in a ViewScoped bean?
Any help is greatly appreciated!
Rob
The pattern you're using doesn't seem to make a lot of sense. There should be no problem with injecting EJBs into a view scoped bean.
Depending on the type of EJB you are using (stateless, stateful or singleton) different things hold.
If the userService and emailService are stateless (they most likely should be), you gain nothing by using a bean that's injected into an application scoped bean first. Namely, what's injected is not the bean itself but a proxy and every request to that is routed to a different real bean instance anyway (see http://en.wikipedia.org/wiki/Enterprise_JavaBean#Stateless_Session_Beans).
If the userService and emailService are stateful, you do get a single instance here, but I highly doubt you need to share actual between every user in your application. But even if you would want that, only a single user (thread) can access the stateful bean at a time.
If those services are singleton, you can just inject them right away into the view scoped bean. There is absolutely no reason to go via an application scoped bean.
Furthermore, ServicesUtil.getUserService() is a static method, so using this to get an injected service is brittle. If you want to use this (you shouldn't, but suppose) ServicesUtil should be injected into UserHandler.
Then, it seems you are confusing CDI and JSF managed beans. I agree this is confusing, but it's currently the way it is. #ViewScoped does not work in combination met CDI beans. From your code it's not clear if #ManagedBean is the JSF variant or the Java EE/CDI one. In this case it should be javax.faces.bean.ManagedBean if you want to use the view scope.
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.