I'm developing a JSF 2.0 app that consumes a SOAP-based web service.
I want to use in the JSFs pages most of the generated client classes for the Web Service - but the client classes are not managed beans (nor CDI beans)... and as there are a lot of client classes I don't think is feasible to add #ManagedBean or #Named annotations to all classes...
Let me give you an example so things might get a bit clearer:
The User class is a generated client class - this class has only two attributes (login and password).
I want to be able to assign values to the attributes of a given user in the JSF page:
<h:inputText value="#{user.name}"/>
<h:inputText value="#{user.password}"/>
And then I want to call my UserService to authenticate the user:
<h:commandButton value="Login" action="#{userService.authenticate}"/>
The only way (AFAIK) to assign a value to the User object from the JSF page is by making the User object a managed bean (or a CDI bean).
As there are more than 100 client classes, I definitely don't want to add #ManagedBean or #Named annotations on all classes (I equally don't want to add message-bean element for each class in the faces-config.xml).
And even if annotating all classes were a feasible option, the solution would have a drawback: the service contract (WSDL) might change at any minute and I would be obligated to regenerate the client classes... I'd loose the annotated classes.
What is the best way to handle this (kind of) issue?
I've looked for a way to declare all classes of a package in the faces-config.xml (example below), but I could find neither a way to do that nor a feasible alternative.
<managed-beans>
<managed-beans-package>x.y.z.ws.client</managed-beans-package>
<managed-beans-scope>none</managed-beans-scope>
</managed-beans>
Just make the User a property of UserService. That's also more conform JSF's MVC ideology. The UserService is the controller and the User is the model.
Thus so,
#ManagedBean
#ViewScoped
public class UserService {
private User user;
// ... (don't forget to prepare user in (post)constructor if "new" user)
}
with
<h:inputText value="#{userService.user.name}" />
<h:inputText value="#{userService.user.password}" />
Related
I have my own realm classes extends AppservPasswordLoginModule and AppservRealm where I get user and roles from my own table in database. In web.xml I defined access to pages and it works.
I have some mechanism to read main menu from my menu.xml file in my bean with #SessionScoped annotation.
I want to use rules from web.xml to display only this items, which user has acces to (defined in web.xml), without repeating configuration in my menu.xml file.
I imagine that the solution might be to check the access to the page when I create menu item for this page in my SessionScoped bean, but I don't know how it could be checked easily.
What is the best solution for this situation?
I'm using glassfish 4.1 and jsf 2.2.
I solved this by the following method:
In my ServletListener
#WebListener
public class implements ServletListener ServletContextListener {...}
I read security-constraint from web.xml, parsing them and store it in my #ApplicationScoped bean.
In #SessionScoped bean, in #PostConstruct annotated method I get all roles stored in #ApplicationScoped bean and checked each individual by
FacesContext.getCurrentInstance().GetExternalContext().IsUserInRole(role);
method.
So I have all current user roles. Then, in my #SessionScoped bean, for each menu item I check whether the resource represented by the url of this menu item is available for roles that current user has.
EDIT: The bad side of this solution is that I analyzing the web.xml file only, without annotations
I have a stateless bean which has a method, where I want to get the current/logged user.
My code to get it:
Principal p1 = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
But I am getting nullpointer exception on this. Why is that?
Or is there any other way to get the logged user?
I am using weblogic.
You're not supposed to grab the FacesContext in an EJB. Even more, your EJBs should be completely free from any JSF dependencies. In other words, you should not have any code imported from javax.faces.* package inside your EJBs. Your EJBs should be designed that way that they are reusable across all different front-ends you can think of such as JSF, JAX-RS, Struts, Spring-MVC and even "plain vanilla" Servlets.
If you're using container managed security or a security framework like Apache Shiro, then you're supposed to use the API-provided facilities for that. In case of "plain vanilla" container managed security (JAAS via web.xml and so on), you're supposed to obtain it form SessionContext (which is rightfully from javax.ejb package) which can be injected as #Resource.
#Resource
private SessionContext context;
public void doSomething() {
Principal principal = context.getCallerPrincipal();
// ...
}
An alternative would be to pass the JPA entity representation of the logged-in user as method argument.
verify the import of the following library:
javax.faces.bean.SessionScoped;
Try again
In my application there are 5 portlets accessing same bean class which is in session scope. My problem is, whenever I open a portlet, managed bean initializes. Managed bean should be initialize once in a session. In my case bean initializing 5 times. Can anyone tell me what is the root cause of that problem?
Here is my bean :
#ManagedBean(name="userManagementBean")
#SessionScoped
public class UserManagementBean {
public UserManagementBean() {
System.out.println("In getter setter bean");
sName=userManagementHelper.findScreenName();
directReport=new DualListModel<String>();
addUserToGroupDual=new DualListModel<String>();
addUserToGroupDual.getSource().clear();
addUserToGroupDual.getTarget().clear();
............
When you annotate your beans with #SessionScoped in Portlet application it is mapped to something as "Portlet Instance Session". This means that this bean will live in session of that portlet, and each portlet has its own session. There is something called "Global Session" which is session shared across all portlets, but as far as I know there is not such annotation in JSF.
JSR286 has user session based scope but it would depend on your portal server if it has the implementation for this as a Custom Scope for JSF.
I know for sure that Websphere portal 8.x supports this.
In Websphere portal 8.x you can specify your managed bean like,
#ManagedBean(name="userManagementBean")
#CustomScoped("#{portletApplicationSessionScope}")
public class UserManagementBean {
...
}
Have a look into your portal server documentation to see if it supports that.
You can use Apache JSF portlet bridge as you have updated that you are using liferay ,
It will expose Application Session Scope as EL,
Add it to application scope in portlet A
PortletSession session = request.getPortletSession();
session.setAttribute("name",name.getValue().toString(),PortletSession.APPLICATION_SCOPE);
and use in portlet B
PortletSession session = request.getPortletSession();
String value = session.getAttribute("name", PortletSession.APPLICATION_SCOPE).toString();
Your xhtml ,
<h:inputText id="itName"
required="true"
value="#{httpSessionScope.name}"/>
I have the following JSF/PrimeFaces EJB architecture:
[JSF/PrimeFaces xhtml view] --> [#ManagedBean JSF bean] --> [#Stateless EJB3 bean] --JPA--> [DB]
That is, the JSF views display entities and collections they access on their backing beans (#ManagedBean) and these collections and entities are in turn fetched by calling stateless EJB3 "facade" beans that have the EntityManager injected and access the database using JPA backed by Hibernate. The stateless EJB3 beans also provide some services but for the most part their role is to provide the Entity objects (JPA-annotated) from the database, as requested by the xhtml views that need to display them.
Now here's the thing: if my understanding is correct, the moment the Entity beans are returned by the stateless EJB3 beans, they become detached as each EJB3 bean method demarcates a transaction. It is then often the case that as the xhtml views and the JSF Managed beans navigate the graphs of the Entity objects so fetched (One-To-Many collections and such), I often get Lazy Initialization exceptions like the following:
javax.el.ELException: ... org.hibernate.LazyInitializationException: failed
to lazily initialize a collection of role: ..., no session or session was closed
The only thing that works is changing collections to be EAGER -ly loaded but that's not a pragmatic solution. What are some good patterns to use when detached JPA entity find their way to the view layer in order to avoid once and for all the lazy initialization exceptions rather than having to treat each case in an ad-hoc manner?
There are two ways of handling lazy associations. The first way is to initialize the entity using:
Hibernate.initialize(proxy)
or set the fetch type to EAGER which will fetch the entire entity when you load it.
The second and the more proper way (in my opinion) is to keep the entity manager as long as you keep the entities. This could be done either using a #Stateful session like this:
#Stateful
public class UserService {
#PersistenceContext(type=EXTENDED)
private EntityManager entityManager;
...... the business method
}
and keep a reference to the ejb as long as you keep the entity. More info about extended persistence context could be found here.
Other way to keep the entity manager is to use CDI modules like seam-persistence or CODI that offer a functionality to create and keep an EntityManager to conversation scope.
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.