I have a problem with CDI scope.
I have a bean with conversation scoped, ClientController, where I have client and phone object to be push in a service order. When I register a new client, I can push one or more phones to this client. For this, I have used conversation scope. However each request to push a new phone to my client is executing the #PostContruct method, doing the bean lose its state, even I am giving begin on the conversation when I push the first phone.
At first, I guess the problem was the bean configuration, but when I removed the template that was declared on the client page, the application works correct. This template use a bean with session scope, to control the page language by the user choice.
Next has my code, and you can follow my code on github repository by this link https://github.com/mcqueide/service-order.
ClientController.java
package br.com.codeshare.controller;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import br.com.codeshare.enums.ErrorCode;
import br.com.codeshare.exception.BusinessException;
import br.com.codeshare.model.Client;
import br.com.codeshare.model.Phone;
import br.com.codeshare.qualifiers.SessionMap;
import br.com.codeshare.service.ClientService;
import br.com.codeshare.service.PhoneService;
import br.com.codeshare.util.WebResources;
#Named
#ConversationScoped
public class ClientController implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private FacesContext facesContext;
#Inject #SessionMap
private Map<String, Object> sessionMap;
#Inject
private ClientService clientService;
private Client newClient;
#Inject
private PhoneController phoneController;
#Inject
private PhoneService phoneService;
#Inject
private Conversation conversation;
private String filterName;
private List<Client> listClients;
private Client clientSelected;
private List<Phone> phoneToBeRemove;
#Produces
#Named
public Client getNewClient() {
return newClient;
}
#PostConstruct
public void initNewClient() {
newClient = new Client();
newClient.setTelefones(new ArrayList<Phone>());
listClients = clientService.findAll();
}
public String save() throws Exception {
try {
validatePhoneLeastOnePhoneObligatory(newClient);
clientService.save(newClient);
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, WebResources.getMessage("register"),WebResources.getMessage("sucess_register")));
initNewClient();
}catch (BusinessException e) {
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,WebResources.getMessage(e.getErrorCode()),"");
facesContext.addMessage(null, m);
}catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,errorMessage,WebResources.getMessage("unsuccessful"));
facesContext.addMessage(null, m);
}
if(!conversation.isTransient()){
conversation.end();
}
return null;
}
public String update(Client client) throws Exception{
try {
validatePhoneLeastOnePhoneObligatory(client);
clientService.update(client,phoneToBeRemove);
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, WebResources.getMessage("register"),WebResources.getMessage("sucess_register")));
initNewClient();
}catch (BusinessException e) {
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,WebResources.getMessage(e.getErrorCode()),"");
facesContext.addMessage(null, m);
return null;
} catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, WebResources.getMessage("unsuccessful"));
facesContext.addMessage(null, m);
return null;
}
if(!conversation.isTransient()){
conversation.end();
}
return "clients";
}
private void validatePhoneLeastOnePhoneObligatory(Client client) throws BusinessException {
if(client.getHomePhone().isEmpty() && client.getBisenessPhone().isEmpty()){
throw new BusinessException(ErrorCode.LEAST_ONE_PHONE_OBLIGATORY.getErrorCode());
}
}
private String getRootErrorMessage(Exception e) {
String errorMessage = "Registration failed. See server log for more information";
if (e == null) {
return errorMessage;
}
Throwable t = e;
while (t != null) {
errorMessage = t.getLocalizedMessage();
t = t.getCause();
}
return errorMessage;
}
public void addClientPhone() {
if(conversation.isTransient()){
conversation.begin();
}
phoneController.getNewPhone().setClient(newClient);
if (newClient.getPhones() == null) {
newClient.setTelefones(new ArrayList<Phone>());
}
newClient.getPhones().add(phoneController.getNewPhone());
phoneController.initNewPhone();
}
public void removeClientPhone(Phone phone){
if(conversation.isTransient()){
conversation.begin();
}
clientSelected.getPhones().remove(phone);
if(phoneToBeRemove == null){
phoneToBeRemove = new ArrayList<Phone>();
}
phoneToBeRemove.add(phone);
}
public void addClientPhoneOnUpdate() {
if(conversation.isTransient()){
conversation.begin();
}
phoneController.getNewPhone().setClient(clientSelected);
if (clientSelected.getPhones() == null) {
clientSelected.setTelefones(new ArrayList<Phone>());
}
clientSelected.getPhones().add(phoneController.getNewPhone());
phoneController.initNewPhone();
}
public void searchByName() {
listClients = null;
if(filterName == null){
listClients = clientService.findAll();
}
listClients = clientService.findByName(filterName);
}
public String edit(Client client) {
if(conversation.isTransient()){
conversation.begin();
}
this.clientSelected = client;
List<Phone> phoneList = phoneService.findPhoneByClientId(clientSelected.getId());
clientSelected.setTelefones(phoneList);
sessionMap.put("client", client);
return "update_client";
}
public Client getClientSelected() {
return (Client) sessionMap.get("client");
}
public String getFilterName() {
return filterName;
}
public void setFilterName(String filterName) {
this.filterName = filterName;
}
public List<Client> getListClients() {
return listClients;
}
}
Language.java
package br.com.codeshare.util;
import java.io.Serializable;
import java.util.Locale;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
#Named
#SessionScoped
public class Language implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private FacesContext facesContext;
#PostConstruct
public void init(){
localeCode = "pt";
countryLocaleCodeChanged();
}
private String localeCode;
public String getLocaleCode() {
return localeCode;
}
public void setLocaleCode(String localeCode) {
this.localeCode = localeCode;
}
// value change event listener
public void countryLocaleCodeChanged() {
facesContext.getViewRoot().setLocale(new Locale(localeCode));
}
}
client.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets" template="/template.xhtml">
<ui:define name="titulo">
#{label['client.title']}
</ui:define>
<ui:define name="body">
<h:form id="form">
<p:messages />
<p:fieldset legend="#{label['client.fieldset.client']}" id="client">
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="name" value="#{label['client.name']}" />
<p:inputText id="name" value="#{newClient.name}" />
<p:outputLabel for="adress" value="#{label['client.adress']}" />
<p:inputText id="adress" value="#{newClient.adress}" />
<p:fragment rendered='#{!language.localeCode.equals("en")}'>
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="homePhone_pt" value="#{label['client.homePhone']}" />
<p:inputMask id="homePhone_pt" value="#{newClient.homePhone}" mask="(99)99999-9999"/>
<p:outputLabel for="bisenessPhone_pt" value="#{label['client.businessPhone']}" />
<p:inputMask id="bisenessPhone_pt" value="#{newClient.bisenessPhone}" mask="(99)9999-9999"/>
</p:panelGrid>
</p:fragment>
<p:fragment rendered='#{language.localeCode.equals("en")}'>
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="homePhone_en" value="#{label['client.homePhone']}" />
<p:inputText id="homePhone_en" value="#{newClient.homePhone}"/>
<p:outputLabel for="bisenessPhone_en" value="#{label['client.businessPhone']}" />
<p:inputText id="bisenessPhone_en" value="#{newClient.bisenessPhone}"/>
</p:panelGrid>
</p:fragment>
</p:panelGrid>
</p:fieldset>
<p:fieldset legend="#{label['client.fieldset.phone']}" id="phones">
<p:panelGrid id="phone" columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="brand" value="#{label['phone.brand']}" />
<p:inputText id="brand" value="#{newPhone.brand}" />
<p:outputLabel for="model" value="#{label['phone.model']}" />
<p:inputText id="model" value="#{newPhone.model}" />
<p:outputLabel for="state" value="#{label['phone.state']}"/>
<p:selectOneRadio id="state" value="#{newPhone.state}">
<f:selectItems value="#{phoneStates}" var="p" itemValue="#{p}" itemLabel="#{label[p.label]}" />
</p:selectOneRadio>
<p:outputLabel for="esn" value="#{label['phone.esn']}" />
<p:inputText id="esn" value="#{newPhone.esn}" />
</p:panelGrid>
<p:commandButton value="#{label['phone.add']}" action="#{clientController.addClientPhone}" update="phoneTable phones"/>
<p:dataTable value="#{newClient.phones}" var="phone" emptyMessage="#{label['phone.notadd']}"
id="phoneTable">
<p:column headerText="#{label['phone.brand']}">
<p:outputLabel value="#{phone.brand}"/>
</p:column>
<p:column headerText="#{label['phone.model']}">
<p:outputLabel value="#{phone.model}"/>
</p:column>
</p:dataTable>
</p:fieldset>
<p:commandButton action="#{clientController.save}" value="#{label['client.save']}" update="#form"/>
</h:form>
</ui:define>
</ui:composition>
template.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:view locale="#{language.localeCode}" encoding="utf-8">
<h:head>
<title>
<ui:insert name="title"/>
</title>
<link rel="stylesheet" type="text/css" href="resources/css/reset.css" />
<link rel="stylesheet" type="text/css" href="resources/css/style.css" />
<link rel="stylesheet" type="text/css" href="resources/css/fonts/font-awesome.min.css" />
</h:head>
<body>
<div class="main">
<div class="menu">
<ui:include src="/menu.xhtml" />
</div>
<div id="body">
<ui:insert name="body"/>
</div>
</div>
</body>
</f:view>
</html>
menu.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition>
<p:menubar>
<p:submenu label="#{label['menu.serviceorder']}">
<p:menuitem value="#{label['menu.serviceorder']}" url="/service-order.jsf"/>
<p:menuitem value="#{label['menu.serviceorder.new']}" url="/new-service-order.jsf"/>
</p:submenu>
<p:submenu label="#{label['menu.client']}">
<p:menuitem value="#{label['menu.client.new']}" url="/client.jsf"></p:menuitem>
<p:menuitem value="#{label['menu.clients']}" url="/clients.jsf"></p:menuitem>
</p:submenu>
</p:menubar>
<h:form class="menu_languages">
<p:selectOneMenu value="#{language.localeCode}">
<f:selectItem itemLabel="Português" itemValue="pt" />
<f:selectItem itemLabel="English" itemValue="en" />
<p:ajax listener="#{language.countryLocaleCodeChanged}" update="#all" />
</p:selectOneMenu>
</h:form>
</ui:composition>
</html>
I am pretty convinced that you are running into one of the following problems:
Conversation ends
try to play with some #PreDestroy methods to see when does the conversation vanish
make sure you do not end() conversations earlier (checking your code that would mean calling save/update)
New conversation is created every time you add phone (this is most likely the cause)
when you want another request to be associated with your running conversation, you need to make use of conversation ID (propagate it)
note that you can obtain the ID by calling conversation.getId()
to verify this, check that your URL contains the given conversation ID
also note that if you every time create a new Conversation, the old long-running ones are still hanging in there
Propagation of Conversation is done by appending a cid (conversation ID) to the request URL. Here is a quote from CDI spec (which I suggest you read) explaining when is conversation propagated automatically:
If the current Servlet request is a JSF request, and the conversation is in long-running state, it is propagated according to the following rules:
The long-running conversation context associated with a request that renders a JSF view is automatically propagated to any faces request (JSF form submission) that originates from that rendered page.
The long-running conversation context associated with a request that results in a JSF redirect (a redirect resulting from a navigation rule or JSF NavigationHandler) is automatically propagated to the resulting non-faces request, and to any other subsequent request to the same URL. This is accomplished via use of a request parameter named cid containing the unique identifier of the conversation.
I could resolved this with this:
<f:metadata>
<f:event listener="#{clientController.initConversation()}" type="preRenderView" />
</f:metadata>
Now when my page is render, I have my cid on my post action. But I don’t know if it is the better way to resolve this, because I want to transform my transaction in long-running just when the user click to add a phone, so if someone has a better idea, share please.
Related
I have a JSF page with a h:selectManyList and a Primefaces commandButton. I want to add new elements to the list when I click the button. The button's action method is called, but elements don't show up in the list. I probably just don't see the forest for the trees.
Page:
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head/>
<h:body>
<h:form id="form">
<h:messages id="errors"/>
<h:selectManyListbox id="listBox" value="#{testBean.availableThings}" style="width:100%">
<f:selectItems value="#{testBean.selectedThings}"/>
</h:selectManyListbox>
<br/>
<p:commandButton id="adder" value="Add" action="#{testBean.addThing}"
ajax="true" update="listBox" process="#this listBox"/>
</h:form>
</h:body>
</html>
Backing bean:
import java.util.ArrayList;
import java.util.List;
import javax.faces.model.SelectItem;
#javax.faces.bean.ManagedBean
#javax.faces.bean.ViewScoped
#com.ocpsoft.pretty.faces.annotation.URLMapping(
id = "testbean",
pattern = "/testbean/",
viewId = "/pages/general/testbean.xhtml")
public class TestBean {
private List<SelectItem> availableThings;
private List<String> selectedThings;
public TestBean() {
availableThings = new ArrayList<>();
selectedThings = new ArrayList<>();
}
public List<SelectItem> getAvailableThings() {
return availableThings;
}
public void setAvailableThings(List<SelectItem> list) {
this.availableThings = list;
}
public List<String> getSelectedThings() {
return selectedThings;
}
public void setSelectedThings(List<String> list) {
this.selectedThings = list;
}
public void addThing() {
availableThings.add(new SelectItem("item", "item")); // I get this message
System.err.println("Added item");
}
}
Why doesn't the added item appear in the list and what do I need to do to make it appear?
You reversed the fields in the xhtml.
<h:selectManyListbox id="listBox" value="#{testBean.availableThings}" style="width:100%">
<f:selectItems value="#{testBean.selectedThings}"/>
</h:selectManyListbox>
Should be
<h:selectManyListbox id="listBox" value="#{testBean.selectedThings}" style="width:100%">
<f:selectItems value="#{testBean.availableThings}"/>
</h:selectManyListbox>
I wanted process data from other bean, in ActionListener method, but it throw NullPointerException, so i try resafe instance of bean to next instance in init() method with #PostConstruct annotation, but it still throw NullPointerException. I know that can obtain bean throught FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(context, expression, expectedType);but is it possible throught #ManagedProperty? This is the code:
Login.java
package sklad;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedProperty;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
public class Login implements ActionListener{
private Osoba os;
#ManagedProperty(value="#{osoba}")
private Osoba osoba;
#PostConstruct
public void init(){
os = osoba;
}
#Override
public void processAction(ActionEvent a) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage("zprava", new FacesMessage(os.getId().toString() + " " + os.getHeslo()));
}
public Osoba getOsoba() {
return osoba;
}
public void setOsoba(Osoba osoba) {
this.osoba = osoba;
}
public Osoba getOs() {
return os;
}
public void setOs(Osoba os) {
this.os = os;
}
}
Osoba.java
package sklad;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
#ManagedBean
#SessionScoped
public class Osoba{
private Integer id;
private String heslo;
public Osoba(){}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getHeslo() {
return heslo;
}
public void setHeslo(String heslo) {
this.heslo = heslo;
}
}
login.xhtml
<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>title</title>
<link rel="stylesheet" type="text/css" href="../styles/login.css" />
</h:head>
<h:body>
<p:growl id="growl" showDetail="true" life="3000" />
<p:panel id="panel_login" header="Přihlášení" styleClass="panel">
<p:panelGrid styleClass="panelGrid">
<h:form>
<p:row>
<p:column>
<h:outputText value="ID: " />
</p:column>
<p:column>
<h:inputText id="id_login" value="${osoba.id}" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputText value="Heslo: " />
</p:column>
<p:column>
<h:inputSecret id="heslo_login" value="${osoba.heslo}" />
</p:column>
</p:row>
<p:row>
<p:column colspan="2">
<h:commandButton id="btn_login" value="Přihlásit">
<f:actionListener type="sklad.Login"/>
</h:commandButton>
</p:column>
</p:row>
</h:form>
</p:panelGrid>
</p:panel>
</h:body>
</html>
The more traditional way of invoking an action listener is to use a method binding, like so:
#ManagedBean
#RequestScoped
public class Login {
...
public void doLogin(ActionEvent event){
// handle action
}
}
And then in the button:
<h:commandButton id="btn_login" value="Přihlásit" actionListener="#{login.doLogin}"/>
This approach has the benefit of turning Login into a ManagedBean, which will make it so the annotations on it will be processed by JSF - and that makes the #ManagedProperty annotation work as expected.
in my JSF2 app I have screens composed with :
Header
Body
In the header I have a combo list. At each change in value in the combo list I have an Ajax request that updates the data in the Body. So far everything is working properly. Now the home screen's structure should be change when the value of combo list change. To do this I have :
1 ManagedBean HomeBean that manage the home
1 ManagedBean HeaderBean that manage the header
2 object HomeScreen1.java and HomeScreen2.java that allows me to valued data from each screen
2 services HomeScreen1Loader.java and HomeScreen2Loader.java that manage loading of each type of screen
1 template home.xhtml
2 fichier home1.xhtml et home2.xhtml
When I log in to the application, I get the good page corresponding (Element type 1 => home page 1). But when I select a type 2 item, the actionListener methode is execute, ManagedBean's data was updated (for type 2 screen) , but the page does not updated. What do you do ?
HeaderBean.java :
package com.omb.view;
import java.io.Serializable;
import java.util.List;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.omb.exception.TechnicalException;
import com.omb.view.util.Constants;
import com.omb.view.util.FacesUtils;
#Controller
#Scope("session")
public class HeaderBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final Log logger = LogFactory.getLog(HeaderBean.class);
private List<SelectItem> elementsDisplayed;
public void initComboList() throws FunctionnalException {
// init the combo list
}
public void elementChangeListener(ValueChangeEvent event) {
if (event.getNewValue() != null) {
// Do traitement....
ContextBean contextBean = (ContextBean) FacesUtils.getObjectInSession(ContextBean.CONTEXT_BEAN_NAME);
AbstractBean currentBean = (AbstractBean) FacesUtils.getObjectInSession(contextBean
.getCurrentBeanInSession());
try {
currentBean.refresh();
} catch (TechnicalException e) {
logger.error(e.getMessage(), e);
}
}
}
public String disconnect() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/login.xhtml?faces-redirect=true";
}
public List<SelectItem> getElementsDisplayed() {
return elementsDisplayed;
}
public void setElementsDisplayed(List<SelectItem> elementsDisplayed) {
this.elementsDisplayed = elementsDisplayed;
}
}
ContextBean.java :
package com.omb.view;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.omb.view.util.Constants;
#Controller
#Scope("session")
public class ContextBean {
public final static String CONTEXT_BEAN_NAME = "contextBean";
private String templateHomeName;
private boolean defaultHome;
public String getTemplateHomeName() {
return this.templateHomeName;
}
public void setTemplateHomeName(String templateHomeName) {
this.templateHomeName = templateHomeName;
}
public boolean isDefaultHome() {
return this.defaultHome;
}
public void setDefaultHome(boolean defaultHome) {
this.defaultHome = defaultHome;
}
}
HomeBean.java :
package com.omb.view.home;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.omb.exception.FunctionnalException;
import com.omb.exception.TechnicalException;
import com.omb.view.AbstractBean;
import com.omb.view.util.Constants;
#Controller
#Scope("session")
public class HomeBean extends AbstractBean {
private static final Log logger = LogFactory.getLog(HomeBean.class);
public static final String HOME_1_NAME = "home1.xhtml";
public static final String HOME_2_NAME = "home2.xhtml";
#Autowired
private HomeScreen1 homeScreen1;
#Autowired
private HomeScreen2 homeScreen2;
#SuppressWarnings({"unchecked", "rawtypes"})
public String display() throws TechnicalException, FunctionnalException {
ContextBean context = (ContextBean) FacesUtils.getObjectInSession(ContextBean.CONTEXT_BEAN_NAME);
if (!isInitialized()) {
if (defaultHomeScreen == null) {
defaultHomeScreen = new DefaultHomeScreen();
}
if (eurHomeScreen == null) {
eurHomeScreen = new EurHomeScreen();
}
AbstractHomeScreenLoader loader = HomeScreenLoaderFactory.getLoader(getTypeElement());
if (Constants.CODE_TYPE_1.equals(getTypeElement()) {
loader.load(homeScreen1);
context.setTemplateHomeName(HOME_1_NAME);
} else {
loader.load(homeScreen2);
context.setTemplateHomeName(HOME_2_NAME);
}
setInitialized(true);
} else if (!upToDate) {
refresh();
}
return "home";
}
#SuppressWarnings({"unchecked", "rawtypes"})
public void refresh() throws TechnicalException {
upToDate = true;
AbstractHomeScreenLoader loader = HomeScreenLoaderFactory.getLoader(getTypeElement());
if (Constants.CODE_TYPE_1.equals(userContext.getCurrentHotelCountryId())) {
loader.refresh(homeScreen1);
} else {
loader.refresh(homeScreen2);
}
}
public HomeScreen1 getHomeScreen1() {
return this.homeScreen1;
}
public void setHomeScreen1(HomeScreen1 homeScreen1) {
this.homeScreen1 = homeScreen1;
}
public HomeScreen2 getHomeScreen2() {
return this.homeScreen2;
}
public void setHomeScreen2(HomeScreen2 homeScreen2) {
this.homeScreen2 = homeScreen2;
}
}
layout.xhtml main template of the application :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:ice="http://www.icesoft.com/icefaces/component">
<h:head>
<title><ui:insert name="title">OMB</ui:insert></title>
<ice:outputStyle href="/xmlhttp/css/xp/xp.css" rel="stylesheet" type="text/css" />
<link type="text/css" rel="stylesheet"
href="#{facesContext.externalContext.requestContextPath}/resources/css/style.css" />
</h:head>
<h:body>
<h:panelGroup id="page" styleClass="mainMaster" layout="block">
<h:panelGroup id="header" styleClass="header" layout="block">
<ui:insert name="header">
<ui:include
src="/pages/layer/header/#{contextBean.templateHeaderName}" />
</ui:insert>
</h:panelGroup>
<h:panelGroup id="headerMenu" styleClass="menu" layout="block">
<ui:insert name="buttons">
<ui:include
src="/pages/layer/menu/#{contextBean.templateMenuButtonName}" />
</ui:insert>
</h:panelGroup>
<h:panelGroup id="main" styleClass="mainContent" layout="block">
<h:panelGroup id="content" styleClass="content" layout="block">
<ui:insert name="content" />
</h:panelGroup>
</h:panelGroup>
<h:panelGroup id="footer" styleClass="footer" layout="block">
<ui:insert name="footer">
<ui:include src="/pages/layer/footer/footer.xhtml" />
</ui:insert>
</h:panelGroup>
</h:panelGroup>
</h:body>
</html>
header.xhtml, page which manage the combo list:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<ui:composition>
<ice:form id="headerForm" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ace="http://www.icefaces.org/icefaces/components"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:panelGroup styleClass="logo" layout="block">
<ice:graphicImage styleClass="imgLogoHR"
value="#{facesContext.externalContext.requestContextPath}/resources/images/common/logo/Logo.png" />
<h:panelGroup styleClass="loginArea" layout="block">
<h:panelGroup styleClass="area" layout="block">
<h:panelGroup styleClass="comboHotel" layout="block">
<ace:simpleSelectOneMenu id="selectCurrentElement"
value="#{headerBean.currentElementDisplayed}"
valueChangeListener="#{headerBean.elementChangeListener}"
labelPosition="left" indicatorPosition="left" required="false"
rendered="#{not empty headerBean.elementsDisplayed}">
<f:selectItems value="#{headerBean.elementsDisplayed}" />
<ace:ajax execute="#this" render="#all" />
</ace:simpleSelectOneMenu>
</h:panelGroup>
</h:panelGroup>
</h:panelGroup>
</h:panelGroup>
</ice:form>
</ui:composition>
</body>
</html>
home.xhtml main template of home page and component should be refresh:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ace="http://www.icefaces.org/icefaces/components">
<h:body>
<ui:composition template="/pages/layer/layout.xhtml">
<ui:define name="content">
<ui:include
src="/pages/home/#{contextBean.templateHomeName}" />
</ui:define>
</ui:composition>
</h:body>
</html>
I found the solution, the problem came to the ManagedBean ContextBean's templateHomeName attribute that was not properly valued. I added in loader.load(homeScreen1) and refresh and everything it's ok. I should upgrade my JSF version : 2.1.0-b11 to 2.1.26 because I had an error when refresh.
I am having trouble adding a p:remoteCommand to a form. It looks something like:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:util="http://java.sun.com/jsf/composite/components/util"
xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Reset Test</title>
<link type="text/css" rel="stylesheet" href="/treetable-sscce/css/example.css" />
<h:outputScript library="primefaces" name="jquery/jquery.js"/>
</h:head>
<div class="box">
<h2>Box</h2>
<h:panelGroup id="mypanel">
Headline: <h:outputText value="#{resetBean.headline}" />
<br/>
Message : <h:outputText value="#{resetBean.message}" />
<br/>
</h:panelGroup>
</div>
<div class="box">
<h2>Form</h2>
<h:form id="myform" acceptcharset="utf-8">
<p:growl id="growl" showDetail="true" sticky="false" severity="info, warn" />
<!-- register custom validate event -->
<f:event listener="#{resetBean.validateForm}" type="postValidate" />
<p:remoteCommand name="resetByEscape" action="#{resetBean.resetAction}"
immediate="true" update=":myform :mypanel" />
<h:outputLabel for="headline">Meldungsüberschrift</h:outputLabel>
<h:inputText id="headline" value="#{resetBean.headline}" />
<br/>
<h:outputLabel for="message">Meldungsüberschrift</h:outputLabel>
<h:inputTextarea id="message" value="#{resetBean.message}" />
<br/>
<h:commandButton action="#{resetBean.resetAction}"
value="Reset" immediate="true" onclick="resetForm()"/>
<h:commandButton action="#{resetBean.submitAction}" value="Submit" immediate="false"/>
</h:form>
</div>
<script type="text/javascript">
<!--//--><![CDATA[//><!--
var resetForm = function()
{
$("[id$='headline']").val(null)
$("[id$='message']").val(null)
}
var escapePressed = function()
{
resetForm();
resetByEscape();
}
$(document).keyup(function(e) {if (e.keyCode == 27) escapePressed();});
//--><!]]>
</script>
</html>
Here is the bean code:
package de.example.beans;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.validator.ValidatorException;
import org.apache.log4j.Logger;
#ViewScoped
#ManagedBean
public class ResetBean implements Serializable
{
private static final long serialVersionUID = 7282752623428425109L;
private static final Logger log = Logger.getLogger(ResetBean.class);
protected String headline = null;
protected String message = null;
public ResetBean() {
log.error("ResetBean");
}
#PostConstruct
public void postConstruct() {
log.error("postConstruct");
}
#PreDestroy
public void preDestroy() {
log.error("preDestroy");
}
public void resetAction() {
log.error("resetAction");
headline = null;
message = null;
}
public void submitAction() {
log.error("submitAction headline="+headline+" message="+message);
}
public void validateForm(ComponentSystemEvent event) throws ValidatorException {
log.error("validateForm");
}
public String getHeadline() {
return headline;
}
public void setHeadline(String headline) {
this.headline = headline;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Both the h:command button and the p:remoteCommand execute the same action in the same fashion. The difference is, that the h:command button responds to a mouse click, while the ESC key triggers the p:remoteCommand via javascript on using ESC key.
The problem is, that the route via p:remoteCommand seems to destroy the backing bean somehow (the bean is #ViewScoped). The #PreDestroy annotated method is never called, however: the next action on the page after using the p:remoteCommand forces the component to be created from scratch! Default constructor and #PostConstruct are called. Naturally some important parameters are missing now and the whole view gets shot to hell.
Any idea what is happening? Why the difference between p:remoteCommmand and h:commandButton in this instance? Any chance of working around the problem?
I could reproduce the problem. In my case and maybe the same case here (question provides only 'sample' code, not real one) it was caused by nested forms template->page.
If you have a ui:composition template or something similar to that, at the end of the generated HTML on client side it may creates nested forms like this:
<h:form>
...
<h:form>
...
</h:form>
...
</h:form>
which is invalid HTML code.
Remove unnecessary forms or reorganize code and test again. It should not call #postConstruct method when p:remoteCommand is called through JavaScript
This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Closed 6 years ago.
Can anyone tel me why command button/link is not getting fired. This welcomePage() should be invoked on button press. I checked the managed property "value" is displaying on the execution, but button or link is not getting invoked.
My loginBean:
import java.io.IOException;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
#ManagedBean(name = "loginBean", eager = true)
#RequestScoped
public class loginBean implements Serializable {
private String value = "This text shows, bean is working ";
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#ManagedProperty(value="#{name}")
public static String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManagedProperty(value="#{password}")
public static String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String welcomePage()
{
System.out.println("welcome user according to user name");
return "customerGreeting.xhtml";
}
}
My index.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core">
<f:view contentType="text/html">
<h:head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Facelet Title</title>
</h:head>
<h:body>
<ui:composition>
<div align ="center">
<h:form id="form" align="center">
<h:panelGrid id="panel" columns="2" >
<f:facet name="header">
<h:outputText value="Login here:"/>
</f:facet>
<h:outputLabel value="Username" />
<p:inputText id="name" value="#{loginBean.name}" />
<h:outputLabel value="Password" />
<p:password id="password" value="#{loginBean.password}" />
<f:facet name="footer">
<h:panelGroup style="display:block; text-align:center">
<p:commandButton id="submit1" value="Submit1" actionListener="#{loginBean.welcomePage}" />
<p:commandLink actionListener="#{loginBean.welcomePage}">
<h:outputText id= "submit2" value="Submit2" />
</p:commandLink>
</h:panelGroup>
</f:facet>
</h:panelGrid>
#{loginBean.value}
</h:form>
</div>
</ui:composition>
</h:body>
</f:view>
</html>
Any help ??
you should use action instead of actionListener, because action needs to return a string for navigation rules