Get properties file from CDI bean - jsf

How can I get a properties file from CDI bean, I mean properties file for internationalization purposes as mentioned here.
In #ManagedBean everything is simple #ManagedProperty(name="....") but I can't encounter the way to achieve the same in CDI bean.
Thank you very much.

As far as I know, CDI doesn't support the kind of field-level access that #ManagedProperty gives (where you can have #ManagedProperty(name="#{msgs.title}")). If you want that level of control in CDI, you'll have to write a CDI Producer.
Considering that the resource bundle is simply a class of ResourceBundle, you could easily obtain your defined bundle with:
FacesContext ctxt = FacesContext.getCurrentInstance();
ResourceBundle bundle = ctxt.getApplication().getResourceBundle(ctxt, aValue);
bundle.get("title");
Alternatively, you could simply inject either your FacesContext or Application into your bean:
#Inject
Application theApplication
public void getBundle{
ResourceBundle bundle = theApplication.getResourceBundle(ctxt, aValue);
}

If you're looking for internationalization support within CDI for JSF purposes, you may want to look at DeltaSpike's JSF module. It builds off of the core i18n support available in core.

Related

JSF 2.2 inject Deltaspike (CDI) windowId into Bean

I'm currently using JSF 2.2 with Deltaspike. We use the Multi-Window-Handling from Deltaspike to handle separate windows. It works great but in a specific case, we need the window ID.
I am able to read it with:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("dswid");
Is there a more elegant way, maybe with injection into my bean?
Regards,
Sebastian
You can use Param from OmniFaces. I find it more elegant, but it is a third libary.
#Inject #Param
private String dswid;
If you don't want to add a library, you can also inject the external context.
#Inject
private ExternalContext externalContext;

How could I read a JSF session bean from a filter?

I'm searching but I can't find the answer, I need secure resources based on permissions, I can't use a filter because FacesContext is not initialized before and I need load the permissions in my session bean. Some solution avoiding use a filter? PhaseListener, ViewHandler and ResourceHandler can't capture an URL resource request, for example I need denied this direct access: http://127.0.0.1:8080/test/resources/images/image.jpg
Thx in advance...
JSF stores session scoped managed beans as an attribute of the HttpSession, which in turn is just available in a Filter by HttpServletRequest#getSession().
HttpSession session = ((HttpServletRequest) request).getSession();
SessionBean sessionBean = session.getAttribute("sessionBean");
// ...
Update: as per the comment you seem to be actually using CDI:
my filter is triggered before than JSF, I always get a null value when I use getAttribute. I'm using CDI with 'Named' and 'SessionScoped' annotations on my Bean because I need use a interceptor to implement security
I understood that you were using JSF's own #ManagedBean and the initial answer only applies to that. If your bean is already managed by CDI's #Named, then just use CDI's own #Inject the usual way in the Filter.
#Inject
private SessionBean sessionBean;
In case of JSF #ManagedBean you should just add a if (sessionBean != null) check. It's irrelevant whether the filter is invoked before JSF servlet or not. Once the session bean has been created by JSF, it won't be null in the filter.

How to call EJB in PhaseListener

I use JSF 2 and EJB 3.1, all of them are deployed on Glassfish 3.1.
When i setup a class named MyInterceptor which is implemented PhaseListener, i can not revoke remote EJB interface inside it.
It notice "NullPointerException ..."
public class MyInterceptor implements PhaseListener {
#EJB(name="AuthorizationEJB",
beanInterface=AuthorizationService.class,
mappedName="corbaname:iiop:localhost:3700#ejb/AuthorizationEJB")
public AuthorizationService authorizationService;
....
}
When I call authorizationService.dosomestuff(), it raise error NullPointerException
How can i do to fix it?
Thank in advance
In JSF 2.1 and earlier, PhaseListeners are unfortunately no injection targets (meaning you can't use injection in them). You can do your lookup programmatically via JNDI instead though.
In JSF 2.2 all JSF artifacts (including PhaseListeners) will be injection targets, but this will probably not help you now.
Unrelated to your question, but I'm not sure what you're trying to achieve by specifying the beanInterface in your annotation. Most likely you'll also don't need the name attribute and if your bean is a local bean you'll also don't need mappedName.
Use a servlet filter instead of a JSF phase listener to do authorization. You can inject an #EJB in a #WebFilter.
Yeah in web filter you could have just used plain #EJB. Maximimum you needed to add beanName if you had two beans implement same AuthorizationService interface.
Servlet filter is per request, I don't think you need to do security stuff at a certain phase from JSF's lifecycle (which is a more granular level than the whole http request).
For normal lookup you can do:
AuthorizationService.class.cast(new InitialContext().lookup("corbaname:iiop:localhost:3700#ejb/AuthorizationEJB")).dosomestuff();
in a try catch javax.naming.NamingException

does this JSF pattern break dependency injection?

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.

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