<p:ajax> not firing when choosing null value - jsf-2

I have the following p:selectOneMenu :
<p:selectOneMenu widgetVar="selectELclUpdateLcl" style="font-size:11px;"
value="#{tabparam.selectedDataEntite}" appendTo="#this"
id="selectedDataEntite" required="true" requiredMessage="Entité obligatoire"
converter="entiteConverter">
<p:ajax event="change" listener="#{tabparam.enableBloc}" update="sBloc sTLocal sEtage" />
<f:selectItem noSelectionOption="true" itemLabel="-- Entités --" value="#{null}"></f:selectItem>
<f:selectItems value="#{tabparam.listDataEntite}" var ="e"
itemLabel="#{e.nom}" itemValue="#{e}" ></f:selectItems>
</p:selectOneMenu>
When I select an item different from null, the ajax event is fired correctly. But if I choose the null one (Select "-- Entités --" ), the ajax event is not fired.
Below is my converter class:
#FacesConverter(value = "entiteConverter")
public class EntiteConverter implements Converter {
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
Data_Entite ret = null;
UIComponent src = arg1;
if (src != null) {
List<UIComponent> childs = src.getChildren();
UISelectItems itens = null;
if (childs != null) {
for (UIComponent ui : childs) {
if (ui instanceof UISelectItems) {
itens = (UISelectItems) ui;
break;
} else if (ui instanceof UISelectItem) {
UISelectItem item = (UISelectItem) ui;
try {
Data_Entite val = (Data_Entite) item.getItemValue();
if (arg2.equals("" + val.getId())) {
ret = val;
break;
}
} catch (Exception e) {
}
}
}
}
if (itens != null) {
List<Data_Entite> values = (List<Data_Entite>) itens.getValue();
if (values != null) {
for (Data_Entite val : values) {
if (arg2.equals("" + val.getId())) {
ret = val;
break;
}
}
}
}
}
return ret;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
String ret = "";
if (arg2 != null && arg2 instanceof Data_Entite) {
Data_Entite m = (Data_Entite) arg2;
if (m != null) {
int id = m.getId();
if (id != 0) {
ret = Integer.toString(id);
}
}
}
return ret;
}
}
Any idea please ? I am using PF 5.1
Thanks.

Related

Assigning one of a <p:selectOneMenu> item in java object

I have a list of governorates that I displayed in a <p:selectOneMenu>
the java code in the managed bean:
public List<SelectItem> gouvernorats() {
List<Gouvernorat> all = emetteursEJB.findAllGouvernorat();
List<SelectItem> items = new ArrayList<>();
for (Gouvernorat g : all) {
items.add(new SelectItem(g, g.getLibelleGouv()));
}
return items;
}
in the <p:selectOneMenu> I add <p:ajax>:
<p:selectOneMenu value="#{emetteurBean.selectedGouvernorat}" style="width:160px" >
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{emetteurBean.gouvernorats()}" />
<p:ajax event="change" listener="#{emetteursBean.handelGouvChanged()"/>
</p:selectOneMenu>
in the method handelGouvChanged() selectedGouvernorat object is always null;
Recently I added the convert I stumbled upon NullPointerException
#FacesConverter(forClass = Gouvernorat.class)
public class EmetteursConverter implements Converter {
#EJB
private ReferentielDaoLocal refEJB;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String selectedValue) {
System.out.println("Inside The Converter");
System.out.println(selectedValue.length());
if (selectedValue == null) {
return null;
} else {
return refEJB.findGouvByCode(selectedValue.trim());
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return null;
} else {
return String.valueOf(((Gouvernorat) value).getIdGouvernorat());
}
}
}
I found a solution, I injected EJB with InitilContext.lookup ()
#FacesConverter(forClass = Gouvernorat.class)
public class GouvernoratConverter implements Converter {
private static final Logger LOG = Logger.getLogger(GouvernoratConverter.class.getName());
#Override
public Object getAsObject(FacesContext context, UIComponent component, String selectedValue) {
if (selectedValue == null) {
return null;
} else {
try {
ReferentielDaoLocal myService = (ReferentielDaoLocal) new
InitialContext().lookup("java:global/ErpCCF/ErpCCF-ejb/ReferentielDaoImpl");
return myService.findGouvByCode(selectedValue);
} catch (NamingException ex) {
LOG.log(Level.SEVERE, "Converter Gouvernorat Error", ex.getMessage());
return null;
}
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return null;
} else {
return String.valueOf(((Gouvernorat) value).getIdGouvernorat());
}
}
}

how to use same List instance variable of backing bean for h:selectOneListbox and h:selectManyListbox

I have a requirement to use same variable of a request scoped backing bean which is a List datatype for h:selectOneListbox and h:selectManyListbox. I get "ip: Validation Error: Value is not valid" error with h:selectOneListbox even after using a converter. Can some one help me resolving this ?
In page1.xhtml I've given it as:
<h:selectManyListbox id="ip" value="#{inputBean.ipAddress}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
</h:selectManyListbox>
In page2.xhtml I've given it as:
<h:selectOneListbox id="ip" value="#{inputBean.ipAddress}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
<f:converter converterId="ipAddressConverter"></f:converter>
</h:selectOneListbox>
My Input bean, a request scoped managed bean looks like this:
#ManagedBean
#RequestScoped
public class InputTablePlot implements Serializable{
private static final long serialVersionUID = 1L;
#ManagedProperty("#{database}")
private Database database;
private Connection connection;
private StringBuilder query;
private PreparedStatement pst_query;
private ResultSet rs;
private List<Long> ipAddress;
private Map<String, Long> ipAddrMenu;
public InputBean()
{
ipAddrMenu = new LinkedHashMap<String, Long>();
}
#PostConstruct
public void init()
{
ipAddrMenu.clear();
try
{
connection = database.getDbConnection();
query = new StringBuilder();
query.append("SELECT distinct source AS ipaddr FROM addrtable ORDER BY source");
pst_query = connection.prepareStatement(query.toString());
rs = pst_query.executeQuery();
while (rs.next())
{
ipAddrMenu.put(ipLongToString(rs.getLong("ipaddr")), rs.getLong("ipaddr")); // Adding
// sources
}
rs.close();
pst_query.close();
connection.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public List<Long> getIpAddress()
{
System.out.println("In Getter" + ipAddress);
return ipAddress;
}
public void setIpAddress(List<Long> ipAddress)
{
System.out.println("In Setter");
System.out.println(ipAddress);
this.ipAddress = ipAddress;
}
public Map<String, Long> getIpAddressList()
{
return ipAddrMenu;
}
public void setIpAddressList(Map<String, Long> ipAddressList)
{
this.ipAddrMenu = ipAddressList;
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((connection == null) ? 0 : connection.hashCode());
result = prime * result + ((database == null) ? 0 : database.hashCode());
result = prime * result + ((ipAddrMenu == null) ? 0 : ipAddrMenu.hashCode());
result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode());
return result;
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
InputBean other = (InputBean) obj;
if (connection == null)
{
if (other.connection != null)
return false;
}
else if (!connection.equals(other.connection))
return false;
if (database == null)
{
if (other.database != null)
return false;
}
else if (!m_database.equals(other.database))
return false;
if (ipAddrMenu == null)
{
if (other.ipAddrMenu != null)
return false;
}
else if (!ipAddrMenu.equals(other.ipAddrMenu))
return false;
if (ipAddress == null)
{
if (other.ipAddress != null)
return false;
}
else if (!ipAddress.equals(other.ipAddress))
return false;
return true;
}
}
Converter code:
import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
public class IpAddressConverter implements Converter
{
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2)
{
List<Long> ipAddr = new ArrayList<Long>();
try{
ipAddr.add(Long.valueOf(arg2));
}catch(NumberFormatException e){
e.printStackTrace();
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage("Problem with conversion of ip!");
facesContext.addMessage(null, facesMessage);
}
for(int i=0; i< ipAddr.size(); i++){
System.out.println("ipAddr >>> "+ipAddr);
}
return ipAddr;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2)
{
String val = null;
try{
Long ip = (Long) arg2;
val = ip.toString();
}catch(Exception e){
e.printStackTrace();
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new FacesMessage("Problem with conversion of ip!");
facesContext.addMessage(null, facesMessage);
}
System.out.println("value >>> "+val);
return val;
}
}
It failed because List<Long> as returned by the converter doesn't match the individual Long item of the available items while JSF is validating the submitted (and converted!) value against the list of available items (as part of safeguard against tampered/spoofed HTTP requests wherein attacker manipulated the selected item value). The converter is supposed to return a Long. All with all, such a converter is simply insuitable for usage in an UISelectOne component.
You'd better bind the value straight to a single property. If you insist in using a List property, then just prepare it with a single empty item and specify the list item index in the value.
private List<Long> ipAddress = new ArrayList<>(1);
with
<h:selectOneListbox id="ip" value="#{inputBean.ipAddress[0]}" size="5">
<f:selectItems value="#{inputBean.ipAddressList}" />
</h:selectOneListbox>
See also:
Validation Error: Value is not valid

PrimeFaces Export data from a Lazyloading DataTable

I want to export a dataTable (with Pagination) having LazyLoad DataModel during Report Generation.
Problem :
When I export, the report is getting generated page by page from Database and then getting exported to Excel/PDF that consumes more time. I would like to get it in a single database access by skipping the page by page generation of dataset.
I'm producing my code snippet as follows:
JSF:
<p:dataTable id="dTable" var="dev" value="#{ReportAction.lazyModel}"
styleClass ="table_paginator" rowKey="#{device.macAddress}" paginatorPosition="bottom"
paginator="true" rowsPerPageTemplate="10,20,30" rows="10" lazy="true"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
emptyMessage="Select appropriate conditions and click 'Generate Report'">
<f:facet name="header">
<h:commandLink actionListener="#{ReportAction.doExport}">
<p:graphicImage value="../../../resources/images/excel.png"
alt="XLS" style="float:right;width:32px;height:32px" />
<p:dataExporter type="xls" target="dTable" fileName="#{ReportAction.fileName}"
preProcessor="#{ReportAction.preProcess}"
postProcessor="#{ReportAction.postProcessXLS}" />
</h:commandLink>
</f:facet>
<!-- All the columns in Data Table -->
</p:dataTable>
Managed Bean:
public class ReportAction {
private ConfigurationReportDataModel mediumConfigModel;
private List<FieldReportModel> configModelList;
private String fileName;
private LazyDataModel<ConfigurationReportModel> lazyModel;
private boolean export;
public ReportAction() {
configModelList = new ArrayList<ConfigurationReportModel>();
export = false;
mediumConfigModel = new ReportDataModel();
}
public void generateFieldReport() {
lazyFieldModel = new ConfigurationReportDataModel(day, fromDate,
location,store,engineer, status, toDate, export);
}
public void preProcess(Object document) {
export = true;
log.info("preProcess::Lazy model : Page Sizing");
if(lazyFieldModel != null) {
lazyFieldModel.setPageSize(1000000);
}
log.info("preProcess::Export All Details");
mediumConfigModel.setExport(true);
}
public void postProcessXLS(Object document) {
HSSFWorkbook wb = (HSSFWorkbook) document;
HSSFSheet sheet = wb.getSheetAt(0);
HSSFRow header = sheet.getRow(0);
HSSFCellStyle cellStyle = wb.createCellStyle();
cellStyle.setFillForegroundColor(HSSFColor.GREEN.index);
cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
for (int i = 0; i < header.getPhysicalNumberOfCells(); i++) {
HSSFCell cell = header.getCell(i);
cell.setCellValue(cell.getStringCellValue().toUpperCase());
cell.setCellStyle(cellStyle);
sheet.autoSizeColumn(i);
}
export = false;
mediumConfigModel.setExport(false);
}
public List<ConfigurationReportModel> getConfigModelList() {
return configModelList;
}
public void setConfigModelList(
ArrayList<ConfigurationReportModel> configModelList) {
this.configModelList = configModelList;
}
public String getFileName() {
SimpleDateFormat formatter = new SimpleDateFormat("ddMMyyyy_HHmmss");
fileName = "Config_Report_".concat(formatter.format(new Date()));
return fileName;
}
public void setMediumConfigModel(
ConfigurationReportDataModel mediumConfigModel) {
this.mediumConfigModel = mediumConfigModel;
}
public void setConfigModelList(
List<ConfigurationReportModel> configModelList) {
this.configModelList = configModelList;
}
public LazyDataModel<ConfigurationReportModel> getLazyFieldModel() {
log.info("##########getLazyFieldModel###########");
if(export) {
log.info("getLazyFieldModel::Will get Exported........");
lazyFieldModel = new ConfigurationReportDataModel(day, fromDate,
location, store, engineer, status, toDate, true);
lazyFieldModel.load(1, 1000000000, null, null, null);
}
return lazyFieldModel;
}
public void setLazyFieldModel(
LazyDataModel<ConfigurationReportModel> lazyFieldModel) {
this.lazyFieldModel = lazyFieldModel;
}
}
DataModel:
public class ConfigurationReportDataModel extends
LazyDataModel<ConfigurationReportModel> {
private List<ConfigurationReportModel> configReport;
private boolean export;
public ConfigurationReportDataModel() {
this.export = false;
}
public List<ConfigurationReportModel> load(int first, int pageSize,
String sortField, SortOrder sortOrder, Map<String, String> filters) {
UIClient client = new UIClient();
ReportData data = null;
// ///////////////////
if(export) {
log.info("Do Export....");
first = 1;
pageSize = 1000000000;
}
deviceList = new ArrayList<DeviceGlobal>();
// Retrieves data from Database with the number of record (page size)
data = client.generateFieldReport(first, pageSize,
Integer.parseInt(location), Integer.parseInt(store),
engineer, getTimeToBeginningOfDay(), getTimeToEndofDay(),
status);
log.info("Obtained data : " + data);
if (data != null) {
log.info("Got devices : " + data.getRecords().size());
deviceList = (ArrayList<DeviceGlobal>) data.getRecords();
// ///////////////////
int record = first + 1;
ConfigurationReportModel storeModel = null;
DeviceGlobal deviceGlobal = null;
configReport = new ArrayList<ConfigurationReportModel>();
for (Iterator<DeviceGlobal> iterator = deviceList.iterator(); iterator
.hasNext();) {
deviceGlobal = (DeviceGlobal) iterator.next();
storeModel = new ConfigurationReportModel(deviceGlobal,
record++);
configReport.add(storeModel);
}
log.info("Total Config Report : " + configReport.size());
// rowCount
int dataSize = data.getReportCount();
this.setRowCount(dataSize);
log.info("Report Count: " + data.getReportCount());
if(export) {
return configReport;
}
else {
// paginate
if (dataSize > pageSize) {
try {
return configReport;
} catch (IndexOutOfBoundsException e) {
return configReport;
}
} else {
return configReport;
}
}
} else {
log.info("Got no devices");
deviceList = new ArrayList<DeviceGlobal>();
configReport = new ArrayList<ConfigurationReportModel>();
this.setRowCount(0);
return configReport;
}
}
}
Note:
There's no syntax error.
All the custom type classes are defined.
How do I get the Excel report by skipping the page by page generation of records?
You have to add pageOnly="false" to dataExporter
for zero devision issue just override an extra LaztDataModel method as given below.
#Override
public void setRowIndex(int rowIndex) {
// TODO Auto-generated method stub
if (rowIndex == -1 || getPageSize() == 0) {
super.setRowIndex(-1);
}
else
super.setRowIndex(rowIndex % getPageSize());
}

Logging the invoked managed bean actionListener in a PhaseListener

I need to log actions fired from managed Bean.This link , Logging the invoked managed bean action in a PhaseListener helps me solve the problem related to actions. But, when I use actionListener , I have a NullPointerException
#Override
public void beforePhase(PhaseEvent event) {
FacesContext context = event.getFacesContext();
if (context.isPostback()) {
UICommand component = findInvokedCommandComponent(context);
if (component != null) {
String methodExpression = component.getActionExpression().getExpressionString();
// It'll contain #{bean.action}.
}
}
}
private UICommand findInvokedCommandComponent(FacesContext context) {
UIViewRoot view = context.getViewRoot();
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
if (context.getPartialViewContext().isAjaxRequest()) {
return (UICommand) view.findComponent(params.get("javax.faces.source"));
} else {
for (String clientId : params.keySet()) {
UIComponent component = view.findComponent(clientId);
if (component instanceof UICommand) {
return (UICommand) component;
}
}
}
return null;
}
THe NullPointerException occurs with line
String methodExpression = component.getActionExpression().getExpressionString();
How can I get the name of the actionListener method ?
I tried
private UICommand findInvokedCommandComponent(FacesContext context) {
UIViewRoot view = context.getViewRoot();
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
if (context.getPartialViewContext().isAjaxRequest()) {
UIComponent component = view.findComponent(params.get("javax.faces.source"));
if (component instanceof UICommand) {
// component.get
UICommand comp= (UICommand) component;
ActionListener[] actionListeners= comp.getActionListeners();
System.out.println("Taille des Listeners : "+actionListeners.length);
ActionListener method;
method = actionListeners[0];
String toString = method.toString();
System.out.println("ActionListener : "+toString);
return (UICommand) component;
}
} else {
for (String clientId : params.keySet()) {
UIComponent component = view.findComponent(clientId);
if (component instanceof UICommand) {
return (UICommand) component;
}
}
}
return null;
}
System.out.println("ActionListener : "+toString); returns ActionListener : `javax.faces.event.MethodExpressionActionListener#16a779b` . What I would like to have is `#{bean.action}` .Maybe I did it the wrong way
You were on the good way, but you need to get the MethodExpressionActionListener which implements the ActionListener. Using it, you still can't get the MethodExpression out of the box, probably the only way is to get it by reflection (not the best thing...).
That said, you can modify your code like this :
if (component != null) {
String methodExpression = "";
if(component.getActionExpression() != null)
{
methodExpression = component.getActionExpression().getExpressionString();
}
else if(component.getActionListeners().length > 0)
{
methodExpression = getActionListener((MethodExpressionActionListener)component.getActionListeners()[0]).getExpressionString();
}
System.out.println("Method Expression : " + methodExpression);
}
And you will need this method to actually get required information out of the MethodExpressionActionListener :
private MethodExpression getActionListener(MethodExpressionActionListener listener)
{
MethodExpression expression = null;
Field field;
try
{
field = listener.getClass().getDeclaredField("methodExpressionZeroArg");
field.setAccessible(true);
expression = (MethodExpression)field.get(listener);
if(expression == null)
{
field = listener.getClass().getDeclaredField("methodExpressionOneArg");
field.setAccessible(true);
expression = (MethodExpression)field.get(listener);
}
}
catch(Exception e)
{
}
return expression;
}

PrimeFaces AutoComplete error

I am facing a strange problem with p:autoComplete, I get following error
java.lang.NumberFormatException: For input string: "player"
My code is as below
xhtml
<p:autoComplete id="schedChemAC" value="#{testMB.selectedPlayer}" completeMethod="#{testMB.completePlay}" process="#this" var="m" itemLabel="#{m.player}" itemValue="#{m}" converter="#{testConverter}">
<p:ajax event="itemSelect" listener="#{testMB.onSelectFrstL}" process="#this"/>
</p:autoComplete>
MBean
public List<Player> getSelectedPlayer() {
return selectedPlayer;
}
public void setSelectedPlayer(List<Player> selectedPlayer) {
this.selectedPlayer = selectedPlayer;
}
public void getName() {
playerName = playerSession.getAll();
}
public List<Player> completePlay(String query) {
List<Player> suggestion = new ArrayList<Player>();
if (playerName == null) {
getName();
}
for (Player c : playerName) {
if (c.getPlayer().toUpperCase().contains(query.toUpperCase())) {
suggestion.add(c);
}
}
return suggestion;
}
public void onSelectFrstL(SelectEvent event) {
}
Converter
#Named(value = "testConverter")
public class TestConverter implements Converter {
#EJB
PlayerSession playSession;
public static List<Player> playLst;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (playLst == null) {
playLst = playSession.getAll();
}
if (value.trim().equals("")) {
return null;
} else {
try {
int number = Integer.parseInt(value);
for (Player c : playLst) {
if (c.getPk() == number) {
return c;
}
}
} catch (Exception ex) {
System.out.println("error");
}
}
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
} else {
return String.valueOf(((Player) value).getPk());
}
}
}
I am not able to find what is wrong in the above code, if i remove the var,itemValue,itemLabel,converter part then it works fine but once i put the var,itemValue,itemLabel,converter code (as given in prime showcase) i get the above error.
Kindly guide me on what is that i am doing wrong or what is that i should check.
Note: My sample table has only two columns, pk(int) & player(string).
I figured out the problem, its basically if i Pass a List to value(AutoComplete) then the Multiple="true" has be used. Whereas to just do one selection i need to pass only Player object to value(AutoComplete).
Hope this helps somebody else who post without understanding how it works (like me).

Resources