How to create a modal dialog with Trinidad and facelets - jsf-2

I am trying to create a modal dialog that pops up when a tr:commandNavigationItem is pressed.
I can get a pop up to appear, and when I click the "cancel" button I created, it will call the returnListener, but the pop up itself won't disappear. Calling the "submit" button causes an exception.
The website is using facelets so the calling page has a template it uses.
I get the following warnings in the log:
W org.apache.myfaces.trinidad.component.UIXComponentBase getClientId getClientId should not be called while the view is being constructed. Component ID: holdOrder_hold
and
W com.ibm.ws.webcontainer.srt.SRTServletResponse setIntHeader SRVE8094W: WARNING: Cannot set header. Response already committed.
Here is the calling page (.xhtml):
<tr:navigationPane hint="bar" inlineStyle="width:100%;" id="completeNavBar">
...
<tr:commandNavigationItem id="holdButton" text="#{odMessages['BUTTON_HOLD_ORDER']}" partialSubmit="true" useWindow="true" rendered="#{taskHandler.holdAndReleaseEnabled}" action="dialog:holdOrder" immidiate="true" returnListener="#{taskHandler.handleReturnHoldDialog}" windowHeight="350" windowWidth="800"/>
...
</tr:navigationPane>
Here is the complete dialog page (.xhtml):
<ui:composition
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:tr="http://myfaces.apache.org/trinidad"
xmlns:trd="http://myfaces.apache.org/trinidad/demo"
xmlns:trh="http://myfaces.apache.org/trinidad/html">
<jsp:directive.page contentType="text/html;charset=utf-8"/>
<f:view>
<tr:document title="Put Order On Hold">
<tr:form>
<tr:messages globalOnly="true"/>
<tr:panelFormLayout>
<tr:inputText id="holdOrder_comment" rows="5" label="Comment:" value="#{taskHandler.task.holdObj.holdComment}" />
<f:facet name="footer">
<tr:commandButton id="holdOrder_hold" actionListener="#{taskHandler.holdToDo}" text="Submit" partialSubmit="true"/>
<tr:commandButton id="holdOrder_cancel" actionListener="#{taskHandler.cancelDialog}" text="cancel" partialSubmit="true"/>
</f:facet>
</tr:panelFormLayout>
</tr:form>
</tr:document>
</f:view>
</ui:composition>
Here is the single backing bean used:
#ManagedBean
#ViewScoped
public class TaskHandler implements Serializable {
...
public void holdToDo(ActionEvent event) {
System.out.println("putting on hold");
HashMap<Object, Object> returnMap = new HashMap<Object, Object>();
try {
boolean response = ToDoHold.execute(task);
if(!response) {
returnMap.put("returnValue", "no validation errors");
}
} catch (Exception e) {
System.out.println("exception in holdToDo");
e.printStackTrace();
}
RequestContext.getCurrentInstance().returnFromDialog(Boolean.TRUE, returnMap);
}
public void handleReturnHoldDialog(ReturnEvent event) {
System.out.println("returning hold Dialog");
}
public void cancelDialog(ActionEvent event) {
System.out.println("cancelling dialog");
try {
HashMap<Object, Object> returnMap = new HashMap<Object, Object>();
returnMap.put("returnValue", "cancel");
RequestContext.getCurrentInstance().returnFromDialog(Boolean.FALSE, returnMap);
} catch(Exception e) {
System.out.println("cancelling dialog: exception");
e.printStackTrace();
}
}
...
}
Versions used:
Trinidad 2.0.1
JSF 2.0
Servlet 3

So I never solved this completely, but it turned out that the problem was using <f:facet name="footer"> in the dialog (the XHTML is available above) was what was causing the problem, and removing the facet caused both buttons to start working correctly. This may be a bug but I'm using a non-up-to-date version of trinidad (1.26) due to corporate guidelines.

Related

Primefaces BlockUI blocks all with widgetvar

i want use Primefaces BlockUI's widgetvar (at the moment i use a modal dialog for it). The application should block only when i select something (a long method will call) and unblock after complete. But it blocks the full side on first side access. Make i something wrong?
When i block the table specific it works. (block="table") But i want block the whole page.
Use Primefaces 5.1 & Mojarra 2.2.8
Short example:
xhtml:
<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:p="http://primefaces.org/ui">
<h:head>
<title>test</title>
</h:head>
<h:body>
<h:form>
<p:blockUI widgetVar="block" blocked="false"/>
<p:dataTable id="table" value="#{myController.tableItems}" rowKey="#{data}"
selection="#{myController.selectedItem}" selectionMode="Single"
var="data">
<p:ajax event="rowSelect" onstart="PF('block').show()"
listener="#{myController.doSomething}"
oncomplete="PF('block').hide()" />
<p:column>#{data}</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
Bean:
#ManagedBean
#ViewScoped
public final class MyController implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private List<String> tableItems;
private String selectedItem;
#PostConstruct
public void init() {
tableItems = new ArrayList<String>();
tableItems.add("test1");
tableItems.add("test2");
}
public void doSomething(SelectEvent event){
System.out.println("DO Something");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(String selectedItem) {
this.selectedItem = selectedItem;
}
public List<String> getTableItems() {
return tableItems;
}
public void setTableItems(List<String> tableItems) {
this.tableItems = tableItems;
}
}
Add an id attribute the body and use that in the block= attribute on the blockui component

How to show validator's message for specific UI component?

Unable to show faces message in xhtml page - its showing in console.
In forgotPassword link, like to check if user exist or not
<h:outputText value="Enter User Name" />
<h:inputText value="#{loginBean.technicianName}" required="true"
requiredMessage="user name is required" id="unameId" >
<f:validator validatorId="com.beans.UserNameAvailableValidator" />
<f:ajax event="blur" render="username_message" />
</h:inputText>
<rich:message for="unameId" id="username_message"/>
bean code:
#FacesValidator("com.beans.UserNameAvailableValidator")
#RequestScoped
public class UserNameAvailableValidator implements Validator {
UserdetailsDAO userdetailsDAO = null;
#Override
public void validate(FacesContext fc, UIComponent uic, Object value) throws ValidatorException {
String userName = (String) value;
userdetailsDAO = new UserdetailsDAOImpl();
try {
if(userdetailsDAO.getUserdetails(userName)!= null) {
System.out.println("user exist");
} else {
throw new ValidatorException(new FacesMessage("Username doesnot exist "));
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
You are only creating the message, you also need to add put it somewhere (the message does not work the same way as exception), in this case you add it to the context:
FacesContext fc = FacesContext.getCurrentInstance();
UIComponent root = fc.getViewRoot();
UIComponent component = root.findComponent("unameId");
fc.addMessage(component.getClientId(fc), new FacesMessage("Username does not exist."));

GET parameters not being passed to ViewScoped ManagedBean

I have a p:dataTable with p:contextMenu and some p:menuitems. One of these menu items should pass on an id to another view which is read like pointed out here.
The thing is the converter throws the required message like the id wasn't sent - and it seems like it truly isn't. I think I'm missing something basic, but I really couldn't figure it out. Here's the code:
The source view
<h:form id="formTabela">
<p:fieldset>
<p:dataTable id="sistemas"
selection="#{sistemaMb.sistemaSelecionado}">
(...)
</p:dataTable>
</p:fieldset>
<p:contextMenu for="sistemas">
<p:menuitem value="Gerenciar módulos" icon="ui-icon-search"
action="modulos?faces-redirect=true&includeViewParams=true"
ajax="false">
<f:param name="id" value="#{sistemaMb.sistemaSelecionado.id}"/>
</p:menuitem>
(More items...)
</p:contextMenu>
(Some dialogs...)
</h:form>
Target view (modulos)
<!-- This is on body: -->
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id" value="#{moduloMb.sistema}"
converterMessage="foo"
required="true"
requiredMessage="bar"/>
<f:event type="preRenderView" listener="#{moduloMb.init()}" />
</f:metadata>
</ui:define>
Target view managed bean
#ManagedBean
#ViewScoped
public class ModuloMb implements Serializable {
private Sistema sistema;
#PostConstruct
public void init() {
if (!Faces.isPostback() && !Faces.isValidationFailed()) {
// business stuff, but "sistema" is always null.
}
}
public Sistema getSistema() {
return sistema;
}
public void setSistema(Sistema sistema) {
this.sistema = sistema;
}
(...)
}
The converter
#FacesConverter(forClass = Sistema.class)
public class SistemaConverter implements Converter {
private final SistemaService sistemaService = lookup(SistemaService.class);
#Override
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
if (value == null || !value.matches("\\d+")) {
return null;
}
Optional<Sistema> optSistema = sistemaService.find(Short.valueOf(value));
if (!optSistema.isPresent())
throw new ConverterException(
new FacesMessage("Id de sistema inválido " + value));
return optSistema.get();
}
#Override
public String getAsString(FacesContext context, UIComponent component,
Object value) {
if (!(value instanceof Sistema) || ((Sistema) value).getId() != null) {
return null;
}
return ((Sistema) value).getId().toString();
}
}
The includeViewParams directive which you use in the outcome string for the p:menuitem tells JSF to insert the special set of view parameters as request parameters in the GET request to your target view.
BUT, f:param does not define a view param and neither will it be appended to the URL to which the GET request is done.
It does work if you append the parameter directly to the implicit navigation outcome: "modulod?faces-redirect=true&id=..."

saving login state with static variable - JSF2

I like to know whats the correct way to create a login/logout mechanizm in jsf2 environment.
I have created a login xhtml form and a Admin bean that stores a static boolean (is_authenticated) . I want to check that variable in every xhtml page , if true? continue , else redirect to login page.
this is Admin.java bean:
#ManagedBean
#SessionScoped
public class Admin implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
static Boolean authenticated;
String username;
String password;
#PostConstruct
public void initialisation() { // init bean on new instance
Admin.authenticated = false;
}
public Boolean getAuthenticated(){
return Admin.authenticated;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String doLogout() {
Admin.authenticated=false;
return "login?faces-redirect=true";
}
public String validity() {
if(username.equals("admin") && password.equals("admin")) {
Admin.authenticated=true;
return "success";
} else {
Admin.authenticated=false;
return "failure";
}
}
}
and this is the main.xhtml:
<?xml version="1.0" encoding="UTF-8" ?>
<ui:composition template="template.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:define name="content">
<c:if test="#{admin.authenticated == false}">
// update Admin.authenticate to false
<meta http-equiv="refresh" content="0;URL=login.xhtml" />
</c:if>
<h1>Statistics</h1>
<div style="margin:10px">
<h:panelGrid columns="3">
Advertisers:
<h:outputText value="#{stats.advertisers}"/>
<h:outputText value=""/>
Publishers:
<h:outputText value="#{stats.publishers}"/>
<h:outputText value=""/>
Campaigns:
<h:outputText value="#{stats.campaigns}"/>
<h:outputText value="(#{stats.activeCampaigns} active)"/>
Banners:
<h:outputText value="#{stats.banners}"/>
<h:outputText value="(#{stats.activeBanners} active)"/>
Games:
<h:outputText value="#{stats.games}"/>
<h:outputText value="(#{stats.activeGames} active)"/>
</h:panelGrid>
</div>
</ui:define>
</ui:composition>
Two questions:
in the jstl 'if' ,I get : "Property 'authenticated' not found on
type com.pkg.name.Admin"
How can I update Admin.authenticate to false from the xhtml file(sorry for the lame question, i'm really new to jsf and web dev in general)
is it good practice to use this static variable? (like an instance of the session variable)
According to me the correct and cleaner way to implement login/logout is to create a filter and apply it to the urls that should be protected(e.g. /admin/*).
If the user sucessfully logs in load his details in session bean. When the user requests a protected page the filter runs first. In the filter get the session from request and call its getAttribute method to get the session bean(jsf stores the session scoped beans as session attributes). If you get the bean object then he is logged in else if you get null he is not authorized and you can redirect him to login page.
For logout you can just call invalidate on the session and all the session scoped attributes will be destroyed.
A working example will be like following:
The SessionScoped bean which will save login information:
UserBean.java
#ManagedBean
#SessionScoped
class UserBean implements Serializable{
private User user;
//getter/setter for user
}
LoginBean.java
#ManagedBean
class LoginBean
{
#ManagedProperty(value="#{userBean}")
private UserBean userBean;
public UserBean getUserBean(){
return userBean;
}
public void setUserBean(UserBean userBean){
this.userBean=userBean;
}
private String username,password;
//getter and setter for username,password
public String checkLogin(){
//check database for user
if(user!=null){
userBean.setUser(user);
}
//...
}
}
LoginFilter.java- We apply this filter to url pattern: /admin/*
#WebFilter("/admin/*")
class LoginFilter implements Filter{
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpSession session=((HttpServletRequest)request).getSession();
userBean userBean=(userBean)session.getAttribute("userBean");
if(userBean!=null){
User user=userBean.getUser();
if(user==null){
((HttpServletResponse)response).sendRedirect("login.jsf");
}
else
chain.doFilter(request, response);
}
else
((HttpServletResponse)response).sendRedirect("login.jsf");
}
public void init(FilterConfig fc){}
public void destroy(){}
}
login.xhtml
<!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"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head><title>Login To Admin Panel</title>
</h:head>
<h:body>
<h:form>
Username : <h:inputText value="#{loginBean.username}"/>
Password : <h:inputSecret value="#{loginBean.password}"/>
<h:commandButton value="Login" action="#{loginBean.checkLogin}" />
</h:form>
</h:body>
</html>
For log out you can simply call session.invalidate() which will destroy the session along with any session scoped attributes.
This way you don't have to write conditional jstl tags to determine whether the use is logged in or not.
Hope this helps.

JSF 2: Navigate to external URL from a backing bean

This is kind of an extension to the question
Navigate to external URL from a backing bean?
I need to invalidate the session in the backing bean method and then forward to an external URL. The outputLink component does not have the capability to invoke an action method (logout method of the bean in this case).
If I use commandLink, the action method gets invoked but after the session is invalidated, another session is created before forwarding to the external URL.
To be more specific: I have a view that loads a list of items on the home page. The home page has a bunch of links (one of them being the logout image/button) on the top that come from a template xhtml. In the template xhtml file, I have the commandLink code that invokes the logout method of the LogoutBean.java. The method gets invoked fine as expected, BUT when I put a break point in the PostConstruct method of the HomeBean, I see that this method is invoked after invalidating the session and then it forwards to the external URL. How to prevent this?
Code:
template.xhtml:
<h:form>
<p:panel id="HomeHeaderPanel" styleClass="tableheaderfont" style="width:98%">
<h:panelGrid id="filterGrid" columns="2" cellpadding="0" styleClass="normalfont" style="width: 98%" columnClasses="leftalign,rightalign">
<h:panelGroup>
<h:link outcome="reviewHome.xhtml?faces-redirect=true" id="homeLink"
title="Review Home">
<h:graphicImage value="images/home_small.png" id="homeIcon" alt="Review Home"/>
</h:link>
<p:spacer width="5"/>
<h:commandLink action="#{logoutBean.logout}" >
<h:graphicImage value="images/logout_small.png" id="logoutIcon" alt="Logout" title="Logout"/>
</h:commandLink>
</h:panelGroup>
</h:panelGrid>
</p:panel>
</h:form>
reviewHome.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui">
<f:view contentType="text/html">
<ui:composition template="template.xhtml">
<ui:define name="content">
<h:form styleClass="form" id="ptpReviewForm">
<f:event listener="#{homeBean.refresh}" type="preRenderView" />...content here...
</h:form>
</ui:define>
</ui:composition>
</f:view>
</html>
HomeBean.java:
#ManagedBean
#SessionScoped
public class HomeBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 3303546811067129792L;
public HomeBean(){}
#EJB
private ReviewEJB reviewEJB;
private List<HomeObject> homeList;
#SuppressWarnings("unused")
#PostConstruct
private void populateItpList()
{
logger.debug("In the PostConstruct method");
homeList = reviewEJB.getList();
}
//This method is loaded every time the Review Home view loads (prerenderView event)
public void refresh()
{
String refresh = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("refresh");
if(null != refresh && refresh.equalsIgnoreCase("true"))
{
homeList = reviewEJB.getList("another");
}
}
LogoutBean.java:
#ManagedBean
#SessionScoped
public class LogoutBean {
public void logout() throws ServletException
{
try {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
((HttpServletRequest) ec.getRequest()).logout();
HttpSession session = (HttpSession) ec.getSession(false);
// invalidate session
if (session != null) {
session.invalidate();
}
ec.redirect("/anotherWebAppContext/forward.jsp?link=review");
} catch (IOException e) {
e.printStackTrace();
}
}
That's caused by the <f:event type="preRenderView"> and the behaviour is fully specified.
Basically you want to kill that event. I've never tried it in this construct, so I can't tell from experience if it works, but you could try to get the events by UIViewRoot#getViewListenersForEventClass() and then clear it out before redirecting.
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
viewRoot.getViewListenersForEventClass(PreRenderViewEvent.class).clear();
// ...
That should in theory work.

Resources