JSF 2: Navigate to external URL from a backing bean - url

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.

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

jsf2 ViewScoped bean initialization

I'm new to jsf technology and I'm trying to understand when and how the ViewScoped jsf bean is initialized.
I have a sample app with 2 beans
ApplicationScopedBean.java
#ManagedBean
#ApplicationScoped
public class ApplicationScopedBean implements Serializable {
private int incrementedCounter =0;
public int getIncrementedCounter() {
incrementedCounter += 1;
return incrementedCounter;
}
}
ViewScopedBean.java
#ManagedBean
#ViewScoped
public class ViewScopedBean implements Serializable {
#ManagedProperty(value = "#{applicationScopedBean}")
private ApplicationScopedBean applicationScopedBean;
private int reincarnationNumber;
private int accessCounter;
#PostConstruct
public void initialize() {
accessCounter = 0;
reincarnationNumber = applicationScopedBean.getIncrementedCounter();
System.out.println("Initializing viewScoped stateManager with reincarnationNumber value = " + String.valueOf(reincarnationNumber));
}
public void noAction() {
//do nothing
}
public int getReincarnationNumber() {
return reincarnationNumber;
}
public int getAccessCounter() {
accessCounter += 1;
return accessCounter;
}
public ApplicationScopedBean getApplicationScopedBean() {
return applicationScopedBean;
}
public void setApplicationScopedBean(ApplicationScopedBean applicationScopedBean) {
this.applicationScopedBean = applicationScopedBean;
}
}
ApplicationScoped bean is created only once for the application launch.
Every time ViewScoped bean is being created, the reincarnationNumber is being increased by 1.
I also have a simple jsf page to display these values:
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:h="http://java.sun.com/jsf/html">
<h:head>
<title>View Scoped bean test</title>
</h:head>
<h:body>
<h:form>
<p>ViewScoped bean reincarnation is <h:outputText value="#{viewScopedBean.reincarnationNumber}"/></p>
<p>ViewScoped bean access counter is <h:outputText value="#{viewScopedBean.accessCounter}"/></p>
<h:commandButton type="submit" value="no action" action="#{viewScopedBean.noAction()}"/>
<h:commandButton type="submit" value="reload this page" action="index"/>
</h:form>
</h:body>
</html>
The problem:
When I launch the application the first time, I already have reincarnationNumber value equal to 3.
In other words, I have this info displayed in browser:
ViewScoped bean reincarnation is 3
ViewScoped bean access counter is 1
Why is that?
Why ViewScoped bean has bean created 3 times?
Thanks in advance!
SOLUTION
As it is stated in the comments, the cause was "start browser" checkbox checked in Run Configurations in my IntelliJ IDEA. The trick is when browser is auto-started from IDE I have viewScopedBean initialized 3 times.
It's not created 3 times, just called the getter several times... and that's because... you can check this answer:
Why JSF calls getters multiple times

How to create a modal dialog with Trinidad and facelets

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.

JSF correct use of dependency

JSF 2.1
Tomcat 7.0
Is this a wrong use of dependency injection?
It works ok moving around the page. But "it works" is not the same as "it's correct".
I would use this pattern also for search purpose. I have a request and i like to use it to populate a table in the same page. Is this possible?
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:h="http://java.sun.com/jsf/html">
<h:head>
<link rel="SHORTCUT ICON" href= "resources/img/onlyT.ico"></link>
<title>title</title>
<h:outputStylesheet library="css" name="compass.css"/>
</h:head>
<h:body>
Login system
<br />
<h:form>
User : <h:inputText value="#{user.username}" />
Password : <h:inputSecret value="#{user.password}" />
<h:commandButton action="#{loginBean.performLogin()}" value="Submit" />
<h:commandButton value="reset" type="reset" />
<h:commandButton value="ChangePsW" action="changePassword"></h:commandButton>
</h:form>
<h:message for="" style="color:red;margin:8px;"/>
</h:body>
</html>
LoginBan.java
#ManagedBean
#RequestScoped
public class LoginBean {
#ManagedProperty(value="#{user}")
private UserBean userBean;
//must povide the setter method
public void setUserBean(UserBean userBean) {
this.userBean = userBean;
}
public LoginBean() {}
public String performLogin(){
//Mi connetto al db
if(userBean.getUsername().equalsIgnoreCase( "mario")){
//effettuo i controlli per stabilire se esiste l'utente
userBean.setRoles("-EE-E-E-E-E-E");
return "/mainPortal/mainPortal";
}
return "/mainPortal/index";
}
}
UserBean.java
#ManagedBean (name="user")
#SessionScoped
public class UserBean implements Serializable {
private String Username;
private String Password;
private String Roles;
/** Creates a new instance of UserBean */
public UserBean() {
}
/**
* #return the Username
*/
public String getUsername() {
return Username;
}
/**
* #param Username the Username to set
*/
public void setUsername( String Username ) {
this.Username = Username;
}
/**
* #return the Password
*/
public String getPassword() {
return Password;
}
/**
* #return the Roles
*/
public String getRoles() {
return Roles;
}
/**
* #param Roles the Roles to set
*/
public void setRoles( String Roles ) {
this.Roles = Roles;
}
/**
* #param Password the Password to set
*/
public void setPassword( String Password ) {
this.Password = Password;
}
change password also use the userBean and has his changePasswordBean.
JSF 2 allows you injecting managed beans in other managed beans. This is only limited by the scope of the bean you're actually injecting, which has to be greater than the scope of the bean you actually are in. I mean, you can inject #SessionScoped bean in a #ViewScoped one, but not in the other way. As you follow that convention, I think you're doing it well.
Generally, your application should be composed by #ViewScoped or #RequestScoped beans to handle current user input/outputs and wider scoped beans for session or application means. So, when user logs in, it's a good idea to maintain his data in a session context, however I suggest you not to maintain user's password into session, at least if you're not going to use it once the login has been succesfully done.
Finally the question you make about search requests, I think you can implement a search input in your page and make your result table load dinamically depending on the search. Just use ajax to obtain it without having to reload the whole page. You can implement everything in a #ViewScoped bean, but remember not to return navigation results in your listener methods if you want to maintain the bean working.

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.

Resources