Get access to session scoped CDI bean from request scoped CDI Bean - jsf-2

I have already one session scoped CDI bean, which keeps currently logged in user data.
Now, from another, request scoped I would like to access to this bean to get some data. I have some operation to do, which is dependent on user login. That's the only information I need.
How to access it?
AccountBean.java:
#Named("accountBean")
#SessionScoped
public class AccountBean implements Serializable {
private static final long serialVersionUID = 16472027766900196L;
#Inject
AccountService accountService;
private String login;
private String password;
// getters and setters ommited
}
Part of login.xhtml:
<h:form>
<h:panelGrid columns="2">
#{msgs.loginPrompt}
<h:inputText id="login" value="#{accountBean.login}" />
#{msgs.passwordPrompt}
<h:inputSecret id="password" value="#{accountBean.password}" />
<h:commandButton value="#{msgs.loginButtonText}"
action="#{accountBean.login}" />
</h:panelGrid>
</h:form>
SearchBean.java:
#Named("searchBean")
#RequestScoped
public class SearchBean {
#Inject AccountBean accountBean;
// some other stuff
}

Just #Inject it.
#Inject
private Bean bean;
Note that this isn't available in the constructor of the receiving bean (it's not possible to inject something in an unconstructed instance, you see). The earliest access point is a #PostConstruct method.
#PostConstruct
public void init() {
bean.doSomething();
}

Related

Referencing managed bean as composite attribute and invoking its method causes MethodNotFoundException [duplicate]

Using JSF 2.0 and EL, I am trying to call a method on a POJO which is an attribute of a viewscoped bean. The code is actually very similar to #BalusC's tutorial here. When I call a method that takes no arguments, everything's fine. But when I try to call a method that takes an argument, I get the following exception:
javax.faces.el.MethodNotFoundException: javax.el.MethodNotFoundException:
/user.xhtml at line 42 and column 32 action="#{users.user.removeFriend(friend)}":
Method not found: model.User#67f2b0dd.removeFriend()
Here are some more details:
user.xhtml
<f:metadata>
<f:viewParam name="id" value="#{users.id}" />
<f:event type="preRenderView" listener="#{users.init}" />
</f:metadata>
...
<h:form id="usersForm">
<p:outputPanel>
<p:dataTable id="userTable" value="#{users.user.friendList}" var="friend">
<p:column>
<h:outputText value="#{friend.name}" />
</p:column>
<p:column>
<p:commandButton action="#{users.user.removeFriend(friend)}"
ajax="true"
update="userTable somethingElse" process="#this"
onerror="errorDialog.show();"
icon="ui-icon-delete"
title="delete user">
</p:commandButton>
</p:column>
</p:dataTable>
</p:outputPanel>
<p:commandButton action="#{users.user.removeAllFriends()}" ajax="true"
update="userTable somethingElse"
process="#this"
icon="ui-icon-close"
value="delete all friends?">
</p:commandButton>
</h:form>
I have the following ViewScoped bean:
Users.java
#ManagedBean(name = "users")
#ViewScoped
public class Users implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private User user;
#ManagedProperty("#{userService}")
private UserService userService; // session scoped
public void init() {
user = userService.getCart(id);
}
public final String getId() {
return id;
}
public final void setId(String id) {
this.id= id;
}
public final User getUser() {
return user;
}
public final void setUser(User user) {
this.user= user;
}
public final void setUserService(UserService userService) {
this.userService = userService;
}
}
The User class - a POJO - has a private List<Friend> friends attribute, with getter and setters and a public method User#removeFriend(Friend f). It has another public method; User#removeAllFriends().
The page renders fine but I get the exception when I click the "Remove" commandButton next to a user in the table.
What's wrong here? Why can I successfully call a parameter-less method but can't pass arguments to another?
Edit: The application is deployed on Tomcat 7.0, if that's any good.
Any help appreciated.
Update: As BalusC and Neo pointed, this is an issue with Tomcat 7.0. I installed WebLogic 12.1 and it all worked fine.
This is a bug in Tomcat. It works when you call the method on the bean directly, but not when you call it on a nested property. I recall this issue as issue 50449 which I have ever reported but was closed as "works for me" (perhaps they did not test it very properly, I didn't find it worth the effort to argue with Tomcat guys again, I haven't had very good experiences with them). In any way, I have re-reported it as issue 52445 with a more solid testcase -I hope.
In the meanwhile, replacing the EL implementation with a different one, from Glassfish for example, should work out. But I can tell you that whatever you're trying to do is not really the proper approach. You've declared a business method on the model (the User entity class) instead of on the controller (the Users managed bean class). This is not right. The model should solely be used to hold the data. The controller should be used to hold the business actions.
I recommend to rewrite your case as follows:
<h:form id="usersForm">
<p:outputPanel>
<p:dataTable id="userTable" value="#{users.user.friends}" var="friend">
<p:column>
<h:outputText value="#{friend.name}" />
</p:column>
<p:column>
<p:commandButton action="#{users.removeFriend(friend)}"
process="#this" update="userTable somethingElse" onerror="errorDialog.show();"
icon="ui-icon-delete" title="delete user" />
</p:column>
</p:dataTable>
</p:outputPanel>
<p:commandButton action="#{users.removeAllFriends}"
process="#this" update="userTable numUsers"
value="delete all friends?" />
</h:form>
and put the business methods in the Users managed bean instead:
public void removeFriend(Friend friend) {
userService.removeFriend(user, friend);
// ...
}
public void removeAllFriends() {
userService.removeAllFriends(user);
// ...
}
Also the UserService being another #ManagedBean is not entirely right. It should actually be an #Stateless EJB, but that's another story. EJBs are not supported on Tomcat anyway without enriching it with for example OpenEJB. Without EJB, it does not necessarily need to be another managed bean. You don't want to expose those services into the view directly.
Ahh.. that explains it # Tomcat.. The way in which you are passing the parameter "#{users.user.removeFriend(friend)}" is EL 2.2. You can overcome that by following the steps here: http://www.mkyong.com/jsf2/how-to-pass-parameters-in-method-expression-jsf-2-0/ OR by using some other way as described here: http://www.mkyong.com/jsf2/4-ways-to-pass-parameter-from-jsf-page-to-backing-bean/. Good luck!
If you are using Tomcat you can do the following.
In the xhtml file you do something like this.
#{ItemInformationController.setFindItem(525)}
#{ItemInformationController.findItem}" var="AVar">
In your controller file you can do something like this:
int itemId;
public List<Item> getFindItem() {
return getJpaController().findLevel3Item(levelId);
}
public void setFindItem(int id) {
itemId= id;
}
This works find with Tomcat 6/7...
enter code here
#ManagedBean(name = "customerBean")
#SessionScoped
public class CustomerBean implements Serializable {
/**/
private static final long serialVersionUID = 1L;
CustomerManager customerManager = CustomerManager.getInstance();
private Book book;
private Long id;
private String name, vorname, addresse, ort;
Customer customer = new Customer();
ArrayList<Customer> customerList;
public void findCustomer(String name){
CustomerManager.getInstance().findCustomerByName(name);
System.out.println("Hello" + customer.getName());
}
getters and setters...
public class CustomerManager {
static EntityManagerFactory emf;
static EntityManager em;
static CustomerManager instance;
EntityTransaction entityTransaction = null;
public CustomerManager() {
emf = Persistence.createEntityManagerFactory("customerRegistration");
em = emf.createEntityManager();
}
List<Customer> customerstList = new ArrayList<Customer>();
Book book = new Book();
Set<Book> bookList = new HashSet<Book>();
Customer customer = new Customer();
public void findCustomerByName(String name) {
// Query for a single object.
Query query = em.createQuery("Select c FROM Customer c WHERE c.name = :name");
query.setParameter("name", name);
System.out.println("Hello from Business");
customer = (Customer)query.getSingleResult();
}
<ui:define name="content">
<h:body>
<h:form id="main">
<p:panelGrid columns="2">
<p:outputLabel for="name" value="#{texts.name}" />
<p:inputText id="name" value="#{customerBean.customer.name}" />
<h:commandButton value="Search"
action="#{customerBean.findCustomer()}" />
</p:panelGrid>
</h:form>
</h:body>
</ui:define>

Dialog close instanciate Bean ViewScoped

I have a form where I have a button, when I click on that button, a Dialog opens to select a value and then my dialog close.
But, doing this my Bean (#ViewScoped) is called again (re-instantiated) and I lose my information that I previous entered on page.
I searched and I found a similar behaviour (http://forum.primefaces.org/viewtopic.php?f=3&t=38235) but no answer.
I initialize my bean with constructor but I don't know if this is the problem.
#ManagedBean(name="exameBean")
#ViewScoped
public class ExameBean implements Serializable {
public ExameBean(){
exame = new Exame();
exames = new ArrayList<Exame>();
}
public void selecionaPaciente() {
RequestContext.getCurrentInstance().openDialog("/pages/SelecionaPaciente");
}
public void retornaPaciente(Paciente paciente) {
RequestContext.getCurrentInstance().closeDialog(paciente);
}
public void pacienteSelecionado(SelectEvent event) {
exame.setPaciente((Paciente) event.getObject());
}
}
SelecionaPaciente.xhtml
<p:column headerText="Selecionar">
<p:commandButton icon="ui-icon-search" actionListener="#{exameBean.retornaPaciente(lista)}" />
</p:column>
May you need to use #SessionScoped, when you use #ViewScoped and show a dialog, you lose the actual instance of you MB. I had the same problem today and i solved using a init method annoted with #PostConstruct (To Load all my data ) and annotate with #SessionScoped to use and manage my data loaded from init().

how to get logged in user id in jsf 2.0

how to get logged in user id in jsf 2.0
I am unable to get the user id. I tried the following methods.
xhtml page
<h:outputText value="#{request.remoteUser}"></h:outputText>
<h:outputText value="#{userDetails.userId}"></h:outputText>
Viewscoped bean class.
public String getUserId() {
FacesContext ctx = FacesContext.getCurrentInstance();
System.out.println ("User"+ctx.getExternalContext().getRemoteUser());
userId =ctx.getExternalContext().getRemoteUser();
return userId;
}
Should i do any initialization in web.xml? or should my bean class extend or implement any other class?

Primefaces #managedBean

i am working with 3.0 M3 . when i declare my managed beans in faces-config.xml, it works perfectly, but when i try the same codes with
annotations #Managed bean #Request Scoped, it says target UN-reachable.
i tried on 2.2 also, but it says same issue again.
I am using glass fish v3
#ManagedBean
#SessionScoped
public class Profile implements Serializable{
private String userId;
private String password;
private int code;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Here is how i call them
<h:form>
<p:panel style="margin-top: 200px;margin-left: 300px;margin-right: 300px;" header="Welcome">
<h:outputText value="Your Code ? "/>
<h:inputText required="true" requiredMessage="Enter user id" value="#{Profile.userId}"/>
<h:outputText value="Password "/>
<h:inputSecret required="true" requiredMessage="Enter password id" value="#Profile.password}"/>
<h:commandButton action="#{Profile.varify}" value="Next"/>
</p:panel>
</h:form>
Profile should be lowercase, and check the syntax on password line
If you don't use the name attribute of the #ManagedBean annotation, you have to refer to the bean with the first letter converted to lower case.
From the #ManagedBean javadoc:
The value of the name() attribute is taken to be the
managed-bean-name. If the value of the name attribute is unspecified
or is the empty String, the managed-bean-name is derived from taking
the unqualified class name portion of the fully qualified class name
and converting the first character to lower case. For example, if the
ManagedBean annotation is on a class with the fully qualified class
name com.foo.Bean, and there is no name attribute on the annotation,
the managed-bean-name is taken to be bean. The fully qualified class
name of the class to which this annotation is attached is taken to be
the managed-bean-class.
Since you are using jsf2
you can do the following - give a name to the bean...
#ManagedBean(name="Profile")
#SessionScoped
public class Profile implements Serializable{
}
Check the import package of #SessionScoped, it must be import javax.faces.bean.SessionScoped;
and also give name to ManageBean #ManagedBean(name="Profile")

View scoped managed bean with setPropertyActionListener

I cant seem to get the view scoped managed bean to work with setPropertyActionListener:
<h:commandButton value="Edit" action="edit-company.xhtml">
<f:setPropertyActionListener target="#{companyHolder.item}" value="#{company}"/>
</h:commandButton>
This works fine if companyHolder is session or request scoped but doesnt work if its view scoped. Is this normal?
A brand new view scoped bean is been created when a new view is created. The target view holds a different instance of the view scoped bean than where the property is been set by the action method on the initial view with the form.
This is at first sight indeed unintuitive, but that's how the view scope works. A view scoped bean lives as long as the view lives. It makes sense after all.
Your best bet is using <f:param> instead of <f:setPropertyActionListener> and let the target view set it by <f:viewParam>.
E.g.
<h:commandButton value="Edit" action="edit-company.xhtml">
<f:param name="companyId" value="#{company.id}"/>
</h:commandButton>
with
<f:metadata>
<f:viewParam name="companyId" value="#{bean.company}" required="true" />
</f:metadata>
and
#ManagedBean
#ViewScoped
public class Bean {
private Company company;
// ...
}
and
#FacesConverter(forClass=Company.class)
public class CompanyConverter implements Converter {
#Override
public void getAsObject(FacesContext context, UIComponent component, Object value) throws ConverterException {
try {
return companyService.find(Long.valueOf(value));
} catch (Exception e) {
throw new ConverterException(new FacesMessage(
String.format("Cannot convert %s to Company", value)), e);
}
}
// ...
}
As a completely different alternative, you can also just navigate back to the same view by returning void or null and render the include conditionally.
<ui:include src="#{bean.editmode ? 'edit' : 'view'}.xhtml" />
This however doesn't work if you require to support GET instead of POST (for which you would need to replace <h:commandButton> by <h:button> by the way).

Resources